Autoindent always uses row above, even when it's empty

Hi, is there some reasonably easy way to make autoindentation use the previous non-empty line when calculating what indentation to use, instead of always using the previous line?

For example:

int main() {
    printf("hello, world");
    // Some empty lines follow:


}

When the cursor is on the last line, with the closing brace }, and I press O to insert above that line, I would want the code to be indented as the comment above, not using the 0-space indentation of the empty lines.

It seems like Kakoune uses file-type specific hooks to handle auto-indentation, so I guess it would be a lot of work to change this for all file types?

I would love an answer to this, too. It’s been an ongoing irritation for me. (I typically experience it when opening a new line with o or O.)

The responsible code appears to be in the c-family-indent-on-newline hook function, in c-family.kak (version from my installation copied below).

It would take me a lot of time to work out how this works, but I expect it is the k and K commands that go up to the previous line to get the indent of that line. a-& is the builtin command to copy the indent from one line to another.

I found c-family-indent-on-newline could be overridden like this in my kakrc file:

hook global -once ModuleLoaded c-family %{                                      
  define-command -override -hidden c-family-indent-on-newline my-c-family-indent-on-newline                                                                           
}           

Then I copy the definition of c-family-indent-on-newline from c-family.kak and change the name to my-c-family-indent-on-newline.

I tried replacing one of the K’s with <a-?>[^\h\n]<ret>, so now I have

    > catch %<                                                                  
        # else indent new lines with the same level as the previous one         
        #execute-keys -draft K <a-&>                             
        execute-keys -draft <a-?>[^\h\n]<ret> <a-&>                             
    >        

It doesn’t work perfectly, though. Probably a similar change would need to be made throughout the rest of the function.

Original version:

define-command -hidden c-family-indent-on-newline %< evaluate-commands -draft -itersel %<
    execute-keys <semicolon>                                                    
    try %<                                                                      
        # if previous line is part of a comment, do nothing                     
        execute-keys -draft <a-?>/\*<ret> <a-K>^\h*[^/*\h]<ret>                 
    > catch %<                                                                  
        # else if previous line closed a paren (possibly followed by words and a comment),
        # copy indent of the opening paren line                                 
        execute-keys -draft kx 1s(\))(\h+\w+)*\h*(\;\h*)?(?://[^\n]+)?\n\z<ret> m<a-semicolon>J <a-S> 1<a-&>
    > catch %<                                                                  
        # else indent new lines with the same level as the previous one         
        execute-keys -draft K <a-&>                                             
    >                                                                           
    # remove previous empty lines resulting from the automatic indent           
    try %< execute-keys -draft k x <a-k>^\h+$<ret> Hd >                         
    # indent after an opening brace or parenthesis at end of line               
    try %< execute-keys -draft k x <a-k>[{(]\h*$<ret> j <a-gt> >                
    # indent after a label                                                      
    try %< execute-keys -draft k x s[a-zA-Z0-9_-]+:\h*$<ret> j <a-gt> >         
    # indent after a statement not followed by an opening brace                 
    try %< execute-keys -draft k x s\)\h*(?://[^\n]+)?\n\z<ret> \               
                               <a-semicolon>mB <a-k>\A\b(if|for|while)\b<ret> <a-semicolon>j <a-gt> >
    try %< execute-keys -draft k x s \belse\b\h*(?://[^\n]+)?\n\z<ret> \        
                               j <a-gt> >                                       
    # deindent after a single line statement end                                
    try %< execute-keys -draft K x <a-k>\;\h*(//[^\n]+)?$<ret> \                
                               K x s\)(\h+\w+)*\h*(//[^\n]+)?\n([^\n]*\n){2}\z<ret> \
                               MB <a-k>\A\b(if|for|while)\b<ret> <a-S>1<a-&> >  
    try %< execute-keys -draft K x <a-k>\;\h*(//[^\n]+)?$<ret> \                
                               K x s \belse\b\h*(?://[^\n]+)?\n([^\n]*\n){2}\z<ret> \
                               <a-S>1<a-&> >                                    
    # deindent closing brace(s) when after cursor                               
    try %< execute-keys -draft x <a-k> ^\h*[})] <ret> gh / [})] <esc> m <a-S> 1<a-&> >
    # align to the opening parenthesis or opening brace (whichever is first)    
    # on a previous line if its followed by text on the same line               
    try %< evaluate-commands -draft %<                                          
        # Go to opening parenthesis and opening brace, then select the most nested one
        try %< execute-keys [c [({],[)}] <ret> >                                
        # Validate selection and get first and last char                        
        execute-keys <a-k>\A[{(](\h*\S+)+\n<ret> <a-K>"(([^"]*"){2})*<ret> <a-K>'(([^']*'){2})*<ret> <a-:><a-semicolon>L <a-S>
        # Remove possibly incorrect indent from new line which was copied from previous line
        try %< execute-keys -draft , <a-h> s\h+<ret> d >                        
        # Now indent and align that new line with the opening parenthesis/brace 
        execute-keys 1<a-&> &                                                   
     > >                                                                        
> >