⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nativeparser.cpp

📁 非常好用的可移植的多平台C/C++源代码编辑器
💻 CPP
📖 第 1 页 / 共 3 页
字号:
    wxFile f(projectCache.GetFullPath(), wxFile::read);
    if (!f.IsOpened())
        return false;

    // read cache file
    Manager::Get()->GetMessageManager()->DebugLog(_("Using parser's existing cache: %s"), projectCache.GetFullPath().c_str());
    bool ret = false;
    try
    {
        ret = parser->ReadFromCache(&f);
    }
    catch (cbException& ex)
    {
        ex.ShowErrorMessage(true);
        ret = false;
    }
    catch (...)
    {
        // eat it
        wxSafeShowMessage(_("Exception thrown!"),_("ERROR"));
        ret = false;
    }
    DisplayStatus(parser, project);
    return ret;
}

bool NativeParser::SaveCachedData(Parser* parser, const wxString& projectFilename)
{
    if (!parser)
        return false;

    wxFileName projectCache = projectFilename;
    projectCache.SetExt(_T("cbCache"));

    wxLogNull ln;
    wxFile f(projectCache.GetFullPath(), wxFile::write);
    if (!f.IsOpened())
    {
        Manager::Get()->GetMessageManager()->DebugLog(_("Failed updating parser's cache: %s"), projectCache.GetFullPath().c_str());
        return false;
    }

    // write cache file
    Manager::Get()->GetMessageManager()->DebugLog(_("Updating parser's cache: %s"), projectCache.GetFullPath().c_str());
    return parser->WriteToCache(&f);
}

void NativeParser::DisplayStatus(Parser* parser, cbProject* project)
{
    if (!parser || !project)
        return;
    long int tim = parser->GetElapsedTime();
    Manager::Get()->GetMessageManager()->DebugLog(_("Done parsing project %s (%d total parsed files, %d tokens in %d.%d seconds)."),
                    project->GetTitle().c_str(),
                    parser->GetFilesCount(),
                    parser->GetTokens().GetCount(),
                    tim / 1000,
                    tim % 1000);
}

int NativeParser::MarkItemsByAI(bool reallyUseAI)
{
    cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();
	if (!ed)
		return 0;

	Parser* parser = FindParserFromActiveEditor();
	if (!parser)
		return 0;

	if (!parser->Done())
		Manager::Get()->GetMessageManager()->DebugLog(_("C++ Parser is still parsing files..."));
	else
	{
		// clear all temporary tokens
		parser->ClearTemporaries();
		bool sort = false;

		// parse function's arguments
		wxString _namespace;
		wxString _procedure;
		if (FindFunctionNamespace(ed, &_namespace, &_procedure))
		{
			Token* token = parser->FindTokenByName(_procedure, false, tkFunction);
			if (token)
			{
				 if (!token->m_Args.IsEmpty() && !token->m_Args.Matches(_T("()")))
				{
					wxString buffer = token->m_Args;
					buffer.Remove(0, 1); // remove (
					buffer.RemoveLast(); // remove )
					buffer.Replace(_T(","), _T(";")); // replace commas with semi-colons
					buffer << _T(';'); // aid parser ;)
					Manager::Get()->GetMessageManager()->DebugLog(_("Parsing arguments: \"%s\""), buffer.c_str());
					if (!parser->ParseBuffer(buffer, false))
						Manager::Get()->GetMessageManager()->DebugLog(_("ERROR parsing block:\n%s"), buffer.c_str());
					sort = true;
				}
			}
		}
		else
			Manager::Get()->GetMessageManager()->DebugLog(_("Could not find current function's namespace..."));

		// parse current code block
		int blockStart = FindCurrentBlockStart(ed);
		if (blockStart != -1)
		{
			++blockStart; // skip {
			int blockEnd = ed->GetControl()->GetCurrentPos();
			wxString buffer = ed->GetControl()->GetTextRange(blockStart, blockEnd);
			if (!parser->ParseBuffer(buffer, false))
				Manager::Get()->GetMessageManager()->DebugLog(_("ERROR parsing block:\n%s"), buffer.c_str());
			sort = true;
		}
		else
			Manager::Get()->GetMessageManager()->DebugLog(_("Could not find current block start..."));

		if (sort)
			parser->SortAllTokens();

		// clear previously marked tokens
		const TokensArray& tokens = parser->GetTokens();
		for (unsigned int i = 0; i < tokens.GetCount(); ++i)
		{
			Token* token = tokens[i];
			token->m_Bool = !reallyUseAI;
		}

        if (!reallyUseAI)
            return tokens.GetCount();

        // AI will mark (m_Bool == true) every token we should include in list
        return AI(ed, parser);
	}
	return 0;
}

const wxString& NativeParser::GetCodeCompletionItems()
{
    m_CCItems.Clear();

	Parser* parser = FindParserFromActiveEditor();
	if (!parser)
		return m_CCItems;

	int count = MarkItemsByAI();
	if (count)
	{
		const TokensArray& tokens = parser->GetTokens();
		for (unsigned int i = 0; i < tokens.GetCount(); ++i)
		{
			Token* token = tokens[i];
			if (!token->m_Bool)
				continue; // not marked by AI
			token->m_Bool = false; // reset flag for next run
			if (!m_CCItems.IsEmpty())
				 m_CCItems << _T(";");
			m_CCItems << token->m_Name << token->m_Args;//" " << token->m_Filename << ":" << token->m_Line;
		}
	}

	return m_CCItems;
}

const wxArrayString& NativeParser::GetCallTips()
{
    m_CallTips.Clear();

    cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();
	if (!ed)
		return m_CallTips;

	Parser* parser = FindParserFromActiveEditor();
	if (!parser)
		return m_CallTips;

	if (!parser->Done())
		return m_CallTips;

	int line = ed->GetControl()->GetCurrentLine();
	wxString lineText = ed->GetControl()->GetLine(line);
	int end = lineText.Length();
	int nest = 0;
	while (end > 0)
	{
		--end;
		if (lineText.GetChar(end) == ')')
			--nest;
		else if (lineText.GetChar(end) == '(')
		{
			++nest;
			if (nest != 0)
				break;
		}
	}
	if (end == 0)
		return m_CallTips; // no (

	lineText.Remove(end);
	Manager::Get()->GetMessageManager()->DebugLog(_("Sending \"%s\" for call-tip"), lineText.c_str());

	// clear previously marked tokens
	const TokensArray& tokens = parser->GetTokens();
	for (unsigned int i = 0; i < tokens.GetCount(); ++i)
	{
		Token* token = tokens[i];
		token->m_Bool = false;
	}

	// AI will mark (m_Bool == true) every token we should include in list
	if (!AI(ed, parser, lineText, true, true))
		return m_CallTips;

	for (unsigned int i = 0; i < tokens.GetCount(); ++i)
	{
		Token* token = tokens[i];
		if (token->m_Bool && !token->m_Args.Matches(_T("()")))
		{
			m_CallTips.Add(token->m_Args);
			token->m_Bool = false; // reset flag for next run
		}
	}

	return m_CallTips;
}

// helper funcs

unsigned int NativeParser::FindCCTokenStart(const wxString& line)
{
	int x = line.Length() - 1;
	int nest = 0;

    bool repeat = true;
    while (repeat)
    {
        repeat = false;
        while (x >= 0 && (isalnum(line.GetChar(x)) || line.GetChar(x) == '_'))
            --x;

        if (x > 0 &&
            (line.GetChar(x) == '>' && line.GetChar(x - 1) == '-') ||
            (line.GetChar(x) == ':' && line.GetChar(x - 1) == ':'))
        {
            x -= 2;
            repeat = true;
        }
        else if (x >= 0 && line.GetChar(x) == '.')
        {
            --x;
            repeat = true;
        }

        if (repeat)
        {
            // check for function/cast ()
            if (x >= 0 && line.GetChar(x) == ')')
            {
                ++nest;
                while (--x >= 0 && nest != 0)
                {
                    switch (line.GetChar(x))
                    {
                        case ')': ++nest; break;
                        case '(': --nest; break;
                    }
                }
                if (x > 0 && (isalnum(line.GetChar(x - 1)) || line.GetChar(x - 1) == '_'))
                    --x;
            }
        }
    }
    ++x;

	if (x < 0)
		x = 0;

    while (line.GetChar(x) == ' ' || line.GetChar(x) == '\t')
        ++x;

	//Manager::Get()->GetMessageManager()->DebugLog("Starting at %d \"%s\"", x, line.Mid(x).c_str());
	return x;
}

wxString NativeParser::GetNextCCToken(const wxString& line, unsigned int& startAt)
{
	wxString res;
	int nest = 0;

    if (startAt < line.Length() && line.GetChar(startAt) == '(')
    {
        while (startAt < line.Length() &&
                (line.GetChar(startAt) == '*' ||
                line.GetChar(startAt) == '&' ||
                line.GetChar(startAt) == '('))
        {
            if (line.GetChar(startAt) == '(')
                ++nest;
            ++startAt;
        }
    }

    //Manager::Get()->GetMessageManager()->DebugLog("at %d (%c): res=%s", startAt, line.GetChar(startAt), res.c_str());
    while (startAt < line.Length() && (isalnum(line.GetChar(startAt)) || line.GetChar(startAt) == '_'))
    {
        res << line.GetChar(startAt);
        ++startAt;
    }

    while (nest > 0 && startAt < line.Length())
    {
        if (line.GetChar(startAt) == ')')
            --nest;
        ++startAt;
    }
    //Manager::Get()->GetMessageManager()->DebugLog("Done nest: at %d (%c): res=%s", startAt, line.GetChar(startAt), res.c_str());

    if (startAt < line.Length() && line.GetChar(startAt) == '(')
    {
        ++nest;
        while (startAt < line.Length() - 1 && nest != 0)
        {
            ++startAt;
            switch (line.GetChar(startAt))
            {
                case ')': --nest; break;
                case '(': ++nest; break;
            }
        }
        ++startAt;
    }

    //Manager::Get()->GetMessageManager()->DebugLog("Return at %d (%c): res=%s", startAt, line.GetChar(startAt), res.c_str());
	return res;
}

wxString NativeParser::GetCCToken(wxString& line, ParserTokenType& tokenType)
{
	// line contains a string on the following form:
	// "    char* mychar = SomeNamespace::m_SomeVar.SomeMeth"
	// first we locate the first non-space char starting from the *end*:
	//
	// "    char* mychar = SomeNamespace::m_SomeVar.SomeMeth"
	//                     ^
	// then we remove everything before it.
	// after it, what we do here, is (by this example) return "SomeNamespace"
	// *and* modify line to become:
	// m_SomeVar.SomeMeth
	// so that if we 're called again with the (modified) line,
	// we 'll return "m_SomeVar" and modify line (again) to become:
	// SomeMeth
	// and so on and so forth until we return an empty string...
	// NOTE: if we find () args in our way, we skip them...

	tokenType = pttSearchText;
	if (line.IsEmpty())
		return wxEmptyString;

	unsigned int x = FindCCTokenStart(line);
	wxString res = GetNextCCToken(line, x);
	//Manager::Get()->GetMessageManager()->DebugLog("FindCCTokenStart returned %d \"%s\"", x, line.c_str());
	//Manager::Get()->GetMessageManager()->DebugLog("GetNextCCToken returned %d \"%s\"", x, res.c_str());

	if (x == line.Length())
		line.Clear();
	else
	{
		//Manager::Get()->GetMessageManager()->DebugLog("Left \"%s\"", line.Mid(x).c_str());
		if (line.GetChar(x) == '.')
		{
			tokenType = pttClass;
			line.Remove(0, x + 1);
		}
		else if ((x < line.Length() - 1 && line.GetChar(x) == '-' && line.GetChar(x + 1) == '>') ||
			(x < line.Length() - 1 && line.GetChar(x) == ':' && line.GetChar(x + 1) == ':'))
		{
			if (line.GetChar(x) == ':')
				tokenType = pttNamespace;
			else
				tokenType = pttClass;
			line.Remove(0, x + 2);
		}
		else
			line.Clear();
	}
	return res;
}

int NativeParser::AI(cbEditor* editor, Parser* parser, const wxString& lineText, bool noPartialMatch, bool caseSensitive)
{
	int count = 0;
    int pos = editor->GetControl()->GetCurrentPos();
	m_EditorStartWord = editor->GetControl()->WordStartPosition(pos, true);
	m_EditorEndWord = pos;//editor->GetControl()->WordEndPosition(pos, true);
	int line = editor->GetControl()->GetCurrentLine();

	wxString searchtext;
	//Manager::Get()->GetMessageManager()->DebugLog("********* START **********");

	Token* parentToken = 0L;
	ParserTokenType tokenType;
	wxString actual;
	int col;
	wxString tabwidth;
	tabwidth.Pad(editor->GetControl()->GetTabWidth(), ' ');
	if (lineText.IsEmpty())
	{
		actual = editor->GetControl()->GetLine(line);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -