Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Checkbox list completion improvements #277

Conversation

AlexandreDoucet
Copy link
Contributor

@AlexandreDoucet AlexandreDoucet commented Jan 2, 2025

I worked on the auto completion for the check boxes and added 2 changes.

  1. The default checkbox text (both checked and unchecked) can now be customized using a new 'raw' field. This update has been reflected in the README. The change was implemented to provide greater flexibility for formatting, depending on the user's setup. For instance, users previously had to manually add a space every time I created a checkbox but now it can be added as the auto-complete text.

     checked = {
         -- Replaces '[x]' of 'task_list_marker_checked'
         raw = '[ ]', -- Optionnal parameter. This can be used to replace variations of the checkbox such as with spaces ('[ ] ',  ' [ ], etc.) or with one of the list char. (- [ ], + [ ] , * [ ])
         icon = '󰱒 ',
         -- Highlight for the checked icon
         highlight = 'RenderMarkdownChecked',
         -- Highlight for item associated with checked checkbox
         scope_highlight = nil,
     },
    
  2. The second change has a bit more impact.
    When the autocomplete checks for the checkbox, it now verifies whether the first non-whitespace character is a list marker ('-', '+', or "*"). Without this check, the autocomplete would insert [ ] or [x], which wouldn't render correctly as a checkbox.

If a marker is detected, the autocomplete will exclude it from its available options.

Without dash present :
image

With dash present :
image

Copy link
Owner

@MeanderingProgrammer MeanderingProgrammer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, thank you for the PR and the feedback!

For the first change since this is based on well-defined markdown syntax I don't want to make the text configurable. I do like the feedback of users needing to manually insert a space being a poor experience, and I think that's something we should do automatically when creating the completion items! Is this a change you could make?

For the second change, I assume this is when you trigger completions manually, or if you have the keyword length set to 0? Since the trigger characters should mean you already typed in the -. Again I like the idea of supporting this out of the box, however I think doing this with tree-sitter would be a little more robust. Rather than string matching the current line we can get the first child node of the current node (which for a list item would be the marker) and check that if it's on the same row as the cursor. This would look something like:

---@private
---@param row integer
---@param node TSNode
---@return string
function M.list_prefix(row, node)
    local marker = node:named_child(0)
    if marker == nil then
        return ''
    end
    local marker_row = marker:range()
    return marker_row == row and '' or '- '
end

You can modify this method to also handle adding a space after the marker to take care of the first problem.

@AlexandreDoucet
Copy link
Contributor Author

Hey thank you for the suggestion and your time,

I will take a look at what you propose as a method, I am not very experienced in neovim plugin coding/systems but if you think it's worth considering as a change it sounds like fun. Worst case, it will exist in my personal fork and be good experience. Also, I am now realizing this probably should have been split in two changes.

To answer your questions, and probably I should have been clearer about the issues I was trying to fix. Bellow are better explanations.


For the first change :

The change could also be an option to have a space be appended to the box since this is what the user needs to do to get the proper rendering from the plugin. Otherwise, without the space it doesn't give you the correct icon automatically but requires the user to add a space manually.

Here is an example :
image
image

Also even github doesn't render it like it's in the markdownguide linked bellow so it's unclear what is supposed to be the expected behavior but I don't think it should be this one.

  • With a space
  • [ ]Without a space

The markdown guide I am using doesn't explicitly state that a space is required to after the ']' but in every example and with other MD renderer I always use a space after. Even the entry in the extended syntax has a space but since it's not explicit stated in the standard, perhaps the real issue is having the case with no space render as a check box.

https://www.markdownguide.org/extended-syntax/
image

Its not a big deal and it may be personal preference, but If I use the auto complete to insert a checkbox, I expect the next characters to be the first input of the list item not the last character for the check box string. This could be fixable with an auto command in the user's config, and it's how I was going to handle it before but I thought it may be worth addressing in the plugin since the change was so simple to add.


For the second, to answer your question it's an issue when you continue the an indented list instead of when you're starting one. It's why i had the behavior be dependent on the context.

Screencast_20250102_192537

The autocomplete behavior should always select the correct option based on whether you start on an empty line or not. I considered including list markers as autocomplete triggers but decided against it because it felt inconsistent and might introduce unintended side effects.

If a list marker is already present on the line (e.g., with no indent), the autocomplete won’t add one. However, if it’s missing, the system will check the previous line for the correct marker and include it.

When inserting a new line at the end of a list, the autocomplete adds indents and suggestions for [ ], [x], and [-]. However, it doesn’t add the list marker (-) by default. This causes the autocomplete to generate an invalid checkbox string, which is unexpected for users. As a result, users must manually add the dash after completing the autocomplete.

Without the list marker, the checkbox doesn’t render properly, which can confuse users when working with the plugin. This discrepancy complicates the process of adding a new list entry and interrupts the expected workflow.

@AlexandreDoucet AlexandreDoucet force-pushed the checkbox_list_completion_improvements branch from 13b7725 to c00cc1e Compare January 3, 2025 00:42
@MeanderingProgrammer
Copy link
Owner

Its not a big deal and it may be personal preference, but If I use the auto complete to insert a checkbox, I expect the next characters to be the first input of the list item not the last character for the check box string. This could be fixable with an auto command in the user's config, and it's how I was going to handle it before but I thought it may be worth addressing in the plugin since the change was so simple to add.

I think that's a great mindset to have and I agree that we should autocomplete as much boilerplate as possible. In terms of which things should be rendered it is ambiguous since shortcut links (which is the thing that happens when you put text in square brackets with no destination) end up behaving differently depending on their context. When they are at the start of a list item and have either a space or an x, they are treated as a checkbox, but a checkbox with no content after don't make sense, so most parsers also require a space. A bit of a loose standard haha.

I think appending a space to all the items for checkboxes by default makes sense! If you want to make that its own PR can merge that in on its own.

@MeanderingProgrammer
Copy link
Owner

The autocomplete behavior should always select the correct option based on whether you start on an empty line or not. I considered including list markers as autocomplete triggers but decided against it because it felt inconsistent and might introduce unintended side effects.

I recently made this change, but need to improve it to handle adding space between the marker and the checkbox.

@MeanderingProgrammer
Copy link
Owner

When inserting a new line at the end of a list, the autocomplete adds indents and suggestions for [ ], [x], and [-]. However, it doesn’t add the list marker (-) by default. This causes the autocomplete to generate an invalid checkbox string, which is unexpected for users. As a result, users must manually add the dash after completing the autocomplete.

This one is going to be a personal preference but I prefer to get some intent from the user. Putting a new line in a list can mean either you're adding a new item, continuing an existing item on a new line, or you're done writing the list and starting some other section.

With those options I think we should only provide suggestions once the user starts a list. A kind of simple way to do that is to only provide suggestions when the cursor is on the same row as the start of the current list item.

Is your preference to provide suggestions kind of whenever possible?

…d intert it into the autocomplete suggestion.
@AlexandreDoucet
Copy link
Contributor Author

AlexandreDoucet commented Jan 3, 2025

Is your preference to provide suggestions kind of whenever possible?

Generally I do, and the way it is handled it in the next version is if the user goes to the next line, they get the suggestion but if they just start typing, it wont auto-complete giving them the option of both. The only issue I have right now is the indent will remain so this may need to be looked into. If the user doesn't want to continue the list, the cursor will start the input on the same indentation as the list.

I may have to think about what I would expect as a user. Perhaps, I would want any inputs that aren't working with the auto-complete to shoot me back to the first column or I have see other systems use an empty checkbox entry as a sign the user was done and remove the checkbox... I am not certain what the best behavior is here.

Also, I am not certain how I messed up my branches so much but trying to revert my changes I accidentally closed my PR and opened one. Apologies for any notification spam/trouble, I have not been doing PRs for very long.

@AlexandreDoucet
Copy link
Contributor Author

I think appending a space to all the items for checkboxes by default makes sense! If you want to make that its own PR can merge that in on its own.

I saw your message after I had made the update to the PR.
Since it's really just adding a space to the already existing hardcoded chars, Il just add it to this one. If you see any more issues with my implementation then Il split it up.

Copy link
Owner

@MeanderingProgrammer MeanderingProgrammer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update, changes look good, just some minor things.

If you have any other improvements after using these for a bit definitely send them my way :)

@@ -38,9 +69,11 @@ function M.items(buf, row, col)
table.insert(items, M.item(component.raw, component.rendered, nil))
end
elseif node:type() == 'list_item' or vim.tbl_contains(list_markers, node:type()) then
local last_marker = M.list_prefix(row, node)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

last_marker -> list_prefix

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I follow, you prefer a change in the name of the variable?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep

@@ -38,9 +69,11 @@ function M.items(buf, row, col)
table.insert(items, M.item(component.raw, component.rendered, nil))
end
elseif node:type() == 'list_item' or vim.tbl_contains(list_markers, node:type()) then
local last_marker = M.list_prefix(row, node)
print(last_marker)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oups good catch, this should have been removed, It was a temporary debug.

table.insert(items, M.item('[ ]', checkbox.unchecked.icon, 'unchecked'))
table.insert(items, M.item('[x]', checkbox.checked.icon, 'checked'))
table.insert(items, M.item(last_marker .. '[ ] ', checkbox.unchecked.icon, 'unchecked'))
table.insert(items, M.item(last_marker .. '[x] ', checkbox.checked.icon, 'checked'))
for name, component in pairs(checkbox.custom) do
table.insert(items, M.item(component.raw, component.rendered, name))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Custom checkboxes should behave the same as checked and unchecked checkboxes:

table.insert(items, M.item(list_prefix .. component.raw .. ' ', component.rendered, name))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

return '' -- Don't run if on the same line, entry should already have a list marker.
end

local start_row = select(1, marker:range())

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

marker_row and start_row have the same value since local value = select(1, ...) and local value = ... are functionally equivalent when it comes to getting the first result of a function call. The string.find example in the Lua docs touches on this: https://www.lua.org/pil/5.2.html.

You can remove this variable and use marker_row when getting marker_line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for linking the exact part of the lua specification that explains this. I made the suggested change in my latest update.

@AlexandreDoucet AlexandreDoucet force-pushed the checkbox_list_completion_improvements branch from ac94763 to b0181b2 Compare January 4, 2025 01:44
Copy link
Owner

@MeanderingProgrammer MeanderingProgrammer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks again!

@MeanderingProgrammer MeanderingProgrammer merged commit cbabe00 into MeanderingProgrammer:main Jan 4, 2025
@AlexandreDoucet AlexandreDoucet deleted the checkbox_list_completion_improvements branch January 4, 2025 02:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants