KTextEditor::Range IncludeHelperCompletionModel::completionRange( KTextEditor::View* view , const KTextEditor::Cursor& position ) { kDebug(DEBUG_AREA) << "cursor: " << position; auto line = view->document()->line(position.line()); auto r = parseIncludeDirective(line, false); if (r.m_range.isValid()) { auto start = line.lastIndexOf('/', r.m_range.end().column() - 1); kDebug(DEBUG_AREA) << "init start=" << start; start = start == -1 ? r.m_range.start().column() : start + 1; kDebug(DEBUG_AREA) << "fixed start=" << start; KTextEditor::Range range( position.line() , start , position.line() , r.m_range.end().column() ); kDebug(DEBUG_AREA) << "selected range: " << range; return range; } kDebug(DEBUG_AREA) << "default select"; #if 0 return KTextEditor::Range(); #else return KTextEditor::CodeCompletionModelControllerInterface3::completionRange(view, position); #endif }
/** * Initiate completion when there is \c #include on a line (\c m_range * in a result of \c parseIncludeDirective() not empty -- i.e. there is some file present) * and cursor placed within that range... despite of completeness of the whole line. */ bool IncludeHelperCompletionModel::shouldStartCompletion( KTextEditor::View* view , const QString& inserted_text , bool user_insertion , const KTextEditor::Cursor& position ) { kDebug(DEBUG_AREA) << "position=" << position << ", inserted_text=" << inserted_text << ", ui=" << user_insertion; m_should_complete = false; auto* doc = view->document(); // get current document auto line = doc->line(position.line()); // get current line auto* iface = qobject_cast<KTextEditor::HighlightInterface*>(doc); // Do nothing if no highlighting interface or not suitable document or // a place within it... (we won't to complete smth in non C++ files or comments for example) if (!iface || !isSuitableDocumentAndHighlighting(doc->mimeType(), iface->highlightingModeAt(position))) return m_should_complete; // Try to parse it... auto r = parseIncludeDirective(line, false); m_should_complete = r.m_range.isValid(); if (m_should_complete) { kDebug(DEBUG_AREA) << "range=" << r.m_range; m_should_complete = position.column() >= r.m_range.start().column() && position.column() <= r.m_range.end().column(); if (m_should_complete) { m_closer = r.close_char(); kDebug(DEBUG_AREA) << "closer=" << m_closer; } } else if (position.column() == line.length()) { auto text = tryToCompleteIncludeDirective(line.mid(0, position.column()).trimmed()); m_should_complete = !text.isEmpty(); if (m_should_complete) { /// \todo Hardcoded angle bracket! Better to check what file was selected /// (from system path or session specific) and replace it accordingly... text += QLatin1String(" <"); auto start = position; start.setColumn(0); auto range = KTextEditor::Range{start, position}; view->document()->replaceText(range, text); } } return m_should_complete; }
/** * Search for \c #include directives * * \invariant Document supposed to have \c KTextEditor::MovingInterface implemented! */ void DocumentInfo::scanForHeadersIncluded(const KTextEditor::Range& source_range) { auto* mv_iface = qobject_cast<KTextEditor::MovingInterface*>(m_doc); assert("No moving iface for document!" && mv_iface); auto range = (source_range == KTextEditor::Range::invalid()) ? m_doc->documentRange() : source_range ; /** * \todo It would be \b cool to have a view class over a document * so the following code would be possible: * \code * for (const auto& l : DocumentLinesView(range, doc)) * { * QString line_str = l; // auto converstion to strings * int line_no = l.index(); // tracking of the current line number * } * // Or even smth like this * DocumentLinesView dv = { view->document() }; * // Get line text by number * QString line_str = dv[line_no]; * \endcode */ // Search lines and filenames #include'd in a selected range for (auto i = range.start().line(); i < range.end().line(); i++) { auto r = parseIncludeDirective(m_doc->line(i), false); if (r.range.isValid()) { r.range.setBothLines(i); kDebug(DEBUG_AREA) << "found #include at" << r.range; if (!isRangeWithSameLineExists(r.range)) addRange( mv_iface->newMovingRange( r.range , KTextEditor::MovingRange::ExpandLeft | KTextEditor::MovingRange::ExpandRight ) , r.type ); else kDebug(DEBUG_AREA) << "range already registered"; } } }
//if-section (# if / # ifdef / #ifndef ) //control-line ( #include / etc ) //# non-directive ( # text newline //text-line (text newline ) bool Preprocessor::parseGroupPart(Item *group) { //cout << "parse group part" << endl; Q_ASSERT(group->toItemComposite()); //look up first significant token Type token = lookAhead(); if(token == Token_eof) return false; //look for '#' if(token != Token_preproc) return parseTextLine(group); //look up first significant token after the '#' token = lookAheadSkipHash(); if(token == Token_eof) return false; // Check if we are at the end of a group. This is not an neccesarely an // error, it happens when we reach an #endif for example. if (token == Token_directive_elif || token == Token_directive_else || token == Token_directive_endif) return false; // if-section? if(token == Token_directive_if || token == Token_directive_ifdef || token == Token_directive_ifndef) return parseIfSection(group); // control-line? if (token == Token_directive_define) return parseDefineDirective(group); if (token == Token_directive_undef) return parseUndefDirective(group); if (token == Token_directive_include) return parseIncludeDirective(group); if (token == Token_directive_error) return parseErrorDirective(group); if (token == Token_directive_pragma) return parsePragmaDirective(group); return parseNonDirective(group); }
/** * We have to stop \c #include completion when current line would parsed well * (i.e. contains complete \c #include expression) or have no \c #include at all. */ bool IncludeHelperCompletionModel::shouldAbortCompletion( KTextEditor::View* view , const KTextEditor::Range& range , const QString& current_completion ) { kDebug(DEBUG_AREA) << "range=" << range << ", current_completion=" << current_completion; kDebug(DEBUG_AREA) << "m_should_complete=" << m_should_complete << ", closer=" << m_closer; // Get current line const auto line = view->document()->line(range.end().line()); // Try to parse it... auto r = parseIncludeDirective(line, false); // nothing to complete for lines w/o #include const auto need_abort = !r.m_range.isValid() || range.end().column() < r.m_range.start().column() || range.end().column() > (r.m_range.end().column() + 1) ; kDebug(DEBUG_AREA) << "result=" << need_abort; return need_abort; }
void IncludeHelperCompletionModel::executeCompletionItem2( KTextEditor::Document* document , const KTextEditor::Range& word , const QModelIndex& index ) const { kDebug(DEBUG_AREA) << "rword=" << word; auto p = index.row() < m_dir_completions.size() ? m_dir_completions[index.row()] : m_file_completions[index.row() - m_dir_completions.size()] ; kDebug(DEBUG_AREA) << "dict=" << p; if (!p.endsWith("/")) // Is that dir or file completion? { // Get line to be replaced and check if #include hase close char... auto line = document->line(word.start().line()); auto r = parseIncludeDirective(line, false); if (r.m_range.isValid() && !r.m_is_complete) p += r.close_char(); } document->replaceText(word, p); }
void IncludeHelperCompletionModel::completionInvoked( KTextEditor::View* view , const KTextEditor::Range& range , InvocationType ) { auto* doc = view->document(); kDebug(DEBUG_AREA) << range << ", " << doc->text(range); const auto& t = doc->line(range.start().line()).left(range.start().column()); kDebug(DEBUG_AREA) << "text to parse: " << t; auto r = parseIncludeDirective(t, false); if (r.m_range.isValid()) { m_should_complete = range.start().column() >= r.m_range.start().column() && range.start().column() <= r.m_range.end().column(); if (m_should_complete) { r.m_range.setBothLines(range.start().line()); kDebug(DEBUG_AREA) << "parsed range: " << r.m_range; m_closer = r.close_char(); updateCompletionList(doc->text(r.m_range), r.m_type == IncludeStyle::local); } } }