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

Wrong indentation for multi-line attributes #108

Open
GergelyKalmar opened this issue Jan 24, 2025 · 3 comments
Open

Wrong indentation for multi-line attributes #108

GergelyKalmar opened this issue Jan 24, 2025 · 3 comments

Comments

@GergelyKalmar
Copy link

It seems that vim auto-indents multi-line attributes as follows:

<img src="test.png" width="10" height="10"
                               alt="test">

I'd prefer if they aligned on the first attribute:

<img src="test.png" width="10" height="10"
     alt="test">

I'm not sure if this behavior is coming from this plugin or somewhere else, but I'm wondering if it's possible to achieve the second option somehow.

@juanMarinero
Copy link

With or without this plugin the indents are for different newlines:

<img src="test.png" width="10" height="10" alt="test">
<img src="test.png" width="10" height="10"
                               alt="test">
<img src="test.png" width="10"
                    height="10" alt="test">
<img src="test.png"
     width="10" height="10" alt="test">
<img src="test.png" width="10"
                    height="10"
                    alt="test">
<img src="test.png"
     width="10"
     height="10"
     alt="test">

Though without any plugin at all (vim -u NONE <file>) the indent is:

<img src="test.png" width="9" height="10"
alt="test" />

Prettier (with default config) indents to just 1 line: <img src="test.png" width="10" height="10" alt="test">. So lets try with a longer <img>, like
<img src="test.png" width="10" height="10" alt="test" onclick="handleClick()" id="testImage" class="image-class" style="border: 1px solid black;" />

Prettier indents to:

<img
    src="test.png"
    width="10"
    height="10"
    alt="test"
    onclick="handleClick()"
    id="testImage"
    class="image-class"
    style="border: 1px solid black"
/>

Thus,

  • If is a collaborative project I recommend you to follow prettier (or alike) configs for that project. Indent as the project leaders command.
  • If you can format as you want, then:
  1. A workaround might be to edit prettier config to suit your indents needs. Later ALE can run it (format) on autosave.

  2. Alternative. Maybe editing hunks with code let indent of indent/html.vim. I guess this is why you opened the issue here and not in Prettier or alike.

@GergelyKalmar
Copy link
Author

GergelyKalmar commented Mar 18, 2025

We're not using Prettier or other auto-formatters at this point (and I'd prefer to keep it this way), so it's more of an editor problem for me personally that I'm trying to solve. Right now I align the continuation lines manually, which is less than ideal.

Not sure I understand the second alternative entirely, but if we can somehow make this plugin fix the problem with the indentation, that would be ideal. If I did understood you correctly, then this plugin doesn't influence vim's default HTML indentation, but please correct me if I'm wrong at that. Even in that case, if the plugin could fix this issue (or provide a configuration option for it that provides better continuation), that would be awesome.

@juanMarinero
Copy link

juanMarinero commented Mar 19, 2025

If I did understood you correctly, then this plugin doesn't influence vim's default HTML indentation, but please correct me if I'm wrong at that

No, I did not communicate it right. What I mean is that maybe this plugin can solve your issue, I guess that it has to do with code hunks alike let indent of indent/html.vim. But that script goes way beyond my understanding.

On the other hand, if this issue could not be solved changing this plugin code, then please consider my auto-formatters advise.

Workaround. Set your cursor on line with opening tag "<" and press <leader>f (normally leader is comma) so it will indent all till line with closing tag ">". If unexpected result then run <leader>f! to see debugging echoes. I coded this quickly, so it must be very improved, but it's a start till someone helps with this plugin code.

nnoremap <leader>f :silent call AlignHTMLTag()<CR>
nnoremap <leader>f! :call AlignHTMLTag()<CR>
function! AlignHTMLTag()
    " Save the current cursor position
    let save_cursor = getpos('.')
    echo "Cursor position saved."

    " Get the current line
    let current_line = getline('.')
    echo "Current line: " . current_line

    " Check if the line contains an HTML-like tag
    if current_line =~ '<[^>]\+'
        echo "HTML-like tag detected."

        " Find the position of the first space after the tag name
        let tag_name_end = match(current_line, '<[^ >]\+')
        let first_space = match(current_line, ' ', tag_name_end)
        echo "First space after tag name at position: " . first_space

        " Calculate the indentation level based on the first space after the tag name
        let indent_level = first_space + 1
        echo "Indentation level: " . indent_level

        " Search for the next '>' character
        let next_close = search('>', 'n')
        echo "Next '>' found at line: " . next_close

        " If a '>' is found, adjust the indentation of the lines in between
        if next_close > 0
            " Set start_line to the current line
            let start_line = line('.')
            " Set end_line to the line containing '>'
            let end_line = next_close
            echo "Adjusting lines from " . start_line . " to " . end_line

            " Ensure start_line is less than or equal to end_line
            if start_line <= end_line
                " Loop through the lines and adjust the indentation
                for line_num in range(start_line + 1, end_line)
                    let line_content = getline(line_num)
                    echo "Original line " . line_num . ": " . line_content

                    " Remove existing leading spaces and add new indentation
                    let new_line = repeat(' ', indent_level) . substitute(line_content, '^\s*', '', '')
                    echo "New line " . line_num . ": " . new_line

                    " Update the line in the buffer
                    call setline(line_num, new_line)
                endfor
            else
                echo "No lines to adjust: start_line > end_line."
            endif
        else
            echo "No '>' found after the current line."
        endif
    else
        echo "No HTML-like tag detected in the current line."
    endif

    " Restore the cursor position
    call setpos('.', save_cursor)
    echo "Cursor position restored."
endfunction

Example. Next

<img src="test.png" width="10" height="10"
                               alt="test">
<img src="test.png" width="10"
                    height="10"
                    alt="test">

is formatted to (setting cursor on 1st line and type <leader>f, then cursor on 4th line and type <leader>f)

<img src="test.png" width="10" height="10"
     alt="test">
<img src="test.png" width="10"
     height="10"
     alt="test">

Tip for multiple consecutive HTML tags to reformat then execute Vim-macros alike (these are not Vim codes but Vim actions):

" start recording the macro f
qf
" go to end of line
$
" find previous "<"
?<
" Set cursor there (press Enter)
<CR>
" run formatter fcn
<leader>f
" find closing ">"
/>
" set cursor there (press Enter)
<CR>
" go 1 line after
j
" stop recording the macro
q

To later call it type @f. So previous example just requires to type 2@f (or 2@@ if the last macro executed was the f one).

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

No branches or pull requests

2 participants