bool ClangCodeCompletionModel::shouldStartCompletion(
    KTextEditor::View* const view
  , const QString& inserted_text
  , const bool user_insertion
  , const KTextEditor::Cursor& pos
  )
{
    auto* const doc = view->document();                     // get current document
    auto result = false;
    auto* const iface = qobject_cast<KTextEditor::HighlightInterface*>(doc);
    if (iface)
    {
        auto is_completion_needed = user_insertion
          && m_plugin->config().autoCompletions()
          && isSuitableDocumentAndHighlighting(doc->mimeType(), iface->highlightingModeAt(pos))
          ;
        if (is_completion_needed)
        {
            auto text = inserted_text.trimmed();
            result = text.endsWith(QLatin1String(".")) || text.endsWith(QLatin1String("->"));
        }
    }
    kDebug(DEBUG_AREA) << "result:" << result;
    return result;
}
/**
 * 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;
}
/**
 * We don't care about how many lines possible was inserted. Just consider
 * a current one.
 */
bool PreprocessorCompletionModel::shouldStartCompletion(
    KTextEditor::View* const view
  , const QString& /*inserted_text*/
  , const bool /*user_insertion*/
  , const KTextEditor::Cursor& position
  )
{
    m_should_complete = false;
    auto* const doc = view->document();                     // get current document
    auto* const 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 false;

    auto text_before = doc->text({KTextEditor::Cursor(position.line(), 0), position});
    kDebug(DEBUG_AREA) << "text_before=" << text_before;
    /// Check if current line starts w/ \c '#' which is a sign of a preprocessor directive.
    if (text_before[0] == '#')
    {
        text_before = text_before.remove(0, 1).trimmed();
        kDebug(DEBUG_AREA) << "again text_before=" << text_before;
        /// Then make sure the text after it, is a subset of some
        /// hardcoded item from the \c COMPLETIONS table.
        m_should_complete = text_before.isEmpty() || std::any_of(
            begin(COMPLETIONS)
          , end(COMPLETIONS)
          , [&text_before](const auto& item)
            {
                auto text = item.text;
                const auto end_of_first_word = text.indexOf(' ');
                if (end_of_first_word != -1)
                    // Strip tail of the completion item... only first word is interesting!
                    text = text.left(end_of_first_word);
                return text_before.size() < text.size() && text.startsWith(text_before);
            }
          );
        kDebug(DEBUG_AREA) << "m_should_complete=" << m_should_complete;
        return m_should_complete;
    }
    return false;
}