Repository: astral-sh/ruff
File: crates/ty_ide/src/completion.rs (Rust)

Code before:

    // Skip over '('.' | '...')*'
    let dots_count = tokens_after_from
        .iter()
        .map(Token::kind)
        .take_while(|t| matches!(t, TokenKind::Dot | TokenKind::Ellipsis))
        .count();

    let tokens_after_dots = &tokens_after_from[dots_count..];

    let (last_token, tokens_after_dots_before_last_name) = tokens_after_dots.split_last()?;

    if last_token.kind() == TokenKind::Name {
        // If we have `from .('.' | '...')* <name>` we can suggest `import`.
        // We check that we must have at least one `.` because we don't want to suggest `import` for `from <name>`.
        //
        // If we have `from ('.' | '...')* dotted_name <name>` we can suggest `import`.
        if (tokens_after_dots_before_last_name.is_empty() && dots_count > 0)
            || is_dotted_name(tokens_after_dots_before_last_name)
        {
            return Some(Completion::keyword("import"));
        }
    }

    None
}

fn is_dotted_name(tokens: &[Token]) -> bool {
    match tokens {
        [] | [_, _] => false,
        [tok] => tok.kind() == TokenKind::Name,
        [dotted_name @ .., penultimate, last] => {
            last.kind() == TokenKind::Name
                && penultimate.kind() == TokenKind::Dot
                && is_dotted_name(dotted_name)
        }
    }
}

/// Order completions according to the following rules:
///
/// 1) Names with no underscore prefix
/// 2) Names starting with `_` but not dunders
/// 3) `__dunder__` names
///
/// Among each category, type-check-only items are sorted last,
/// and otherwise completions are sorted lexicographically.
///
/// This has the effect of putting all dunder attributes after "normal"
/// attributes, and all single-underscore attributes after dunder attributes.
fn compare_suggestions(c1: &Completion, c2: &Completion) -> Ordering {

Review comment (suggestion):
I think this routine should be modeled on this existing function:

https://github.com/astral-sh/ruff/blob/f44598dc113a7380ca52d6c969431ca929a93473/crates/ty_ide/src/completion.rs#L667-L756

Maybe there is a way to factor out the common logic, but even if there isn't, just copying the _approach_ seems like the right move here. I agree with @MichaReiser above. And notice that the function above is careful to not do too much look-behind on the token sequence. It also handles things like ellipsis, non-logical newlines and so on.

Code after:
    if last.end() < offset {
        return None;
    }
    Some(source[last.range()].to_string())
}

/// Whether the last token is in a place where we should not provide completions.
fn is_in_no_completions_place(db: &dyn Db, tokens: &[Token], file: File) -> bool {
    is_in_comment(tokens) || is_in_string(tokens) || is_in_definition_place(db, tokens, file)
}

/// Whether the last token is within a comment or not.
fn is_in_comment(tokens: &[Token]) -> bool {
    tokens.last().is_some_and(|t| t.kind().is_comment())
}

/// Whether the last token is positioned within a string token (regular, f-string, t-string, etc).
///
/// Note that this will return `false` when the last token is positioned within an
/// interpolation block in an f-string or a t-string.
fn is_in_string(tokens: &[Token]) -> bool {
    tokens.last().is_some_and(|t| {
        matches!(
            t.kind(),
            TokenKind::String | TokenKind::FStringMiddle | TokenKind::TStringMiddle
        )
    })
}

/// Returns true when the tokens indicate that the definition of a new name is being introduced at the end.
fn is_in_definition_place(db: &dyn Db, tokens: &[Token], file: File) -> bool {
    let is_definition_keyword = |token: &Token| {
        if matches!(
            token.kind(),
            TokenKind::Def | TokenKind::Class | TokenKind::Type
        ) {
            true
        } else if token.kind() == TokenKind::Name {
            let source = source_text(db, file);
            &source[token.range()] == "type"
        } else {
            false
        }
    };

    tokens
        .len()
        .checked_sub(2)
        .and_then(|i| tokens.get(i))
        .is_some_and(is_definition_keyword)
}