Repository: helix-editor/helix
File: helix-core/src/comment.rs (Rust)

Code before:
//! This module contains the functionality toggle comments on lines over the selection
//! using the comment character defined in the user's `languages.toml`

use smallvec::SmallVec;

use crate::{
    syntax::BlockCommentToken, Change, Range, Rope, RopeSlice, Selection, Tendril, Transaction,
};
use helix_stdx::rope::RopeSliceExt;
use std::borrow::Cow;

pub const DEFAULT_COMMENT_TOKEN: &str = "//";

/// Returns the matching comment token of the given line (if it exists).
pub fn get_comment_token<'a>(
    text: &Rope,
    tokens: Option<&'a Vec<String>>,
    line_num: usize,
) -> Option<&'a str> {
    let text = text.slice(..);
    let mut token_found = false;

    if let Some(tokens) = tokens {
        let mut final_token = tokens
            .first()
            .map(|token| token.as_str())
            .unwrap_or(DEFAULT_COMMENT_TOKEN);

        for token in tokens {
            let (is_commented, _, _, _) = find_line_comment(token, text, [line_num]);

            if is_commented {
                token_found = true;

                // in rust for example, there's `//` and `///`.
                // We need to find the longest matching comment token so we can't immediately return the first matching token.
                if token.len() > final_token.len() {
                    final_token = token;
                }
            }
        }


Review comment (suggestion):
I don't think we should be trying to continue comments if a language doesn't configure comment token(s). Similarly I'm not sure we should be doing anything when using C-c on plaintext or a language that doesn't define comments. I think it's fine if this feature doesn't work on plaintext.

Code after:
//! This module contains the functionality toggle comments on lines over the selection
//! using the comment character defined in the user's `languages.toml`

use smallvec::SmallVec;

use crate::{
    syntax::BlockCommentToken, Change, Range, Rope, RopeSlice, Selection, Tendril, Transaction,
};
use helix_stdx::rope::RopeSliceExt;
use std::borrow::Cow;

pub const DEFAULT_COMMENT_TOKEN: &str = "//";

/// Returns the longest matching comment token of the given line (if it exists).
pub fn get_comment_token<'a, S: AsRef<str>>(
    text: RopeSlice,
    tokens: &'a [S],
    line_num: usize,
) -> Option<&'a str> {
    let line = text.line(line_num);
    let start = line.first_non_whitespace_char()?;

    tokens
        .iter()
        .map(AsRef::as_ref)
        .filter(|token| line.slice(start..).starts_with(token))
        .max_by_key(|token| token.len())
}

/// Given text, a comment token, and a set of line indices, returns the following:
/// - Whether the given lines should be considered commented
///     - If any of the lines are uncommented, all lines are considered as such.
/// - The lines to change for toggling comments
///     - This is all provided lines excluding blanks lines.
/// - The column of the comment tokens
///     - Column of existing tokens, if the lines are commented; column to place tokens at otherwise.
/// - The margin to the right of the comment tokens
///     - Defaults to `1`. If any existing comment token is not followed by a space, changes to `0`.
fn find_line_comment(
    token: &str,
    text: RopeSlice,
    lines: impl IntoIterator<Item = usize>,