runtime(karel): Add indent plugin for Karel

Commit: 
https://github.com/vim/vim/commit/f31407f9fa7e38ba63bc0c7abe532db98a21532b
Author: Patrick Meiser-Knosowski <[email protected]>
Date:   Fri May 29 18:19:39 2026 +0000

    runtime(karel): Add indent plugin for Karel
    
    closes: https://github.com/vim/vim/issues/20357
    
    Signed-off-by: Patrick Meiser-Knosowski <[email protected]>
    Signed-off-by: Christian Brabandt <[email protected]>

diff --git a/.github/MAINTAINERS b/.github/MAINTAINERS
index 4c4873507..58a8f9456 100644
--- a/.github/MAINTAINERS
+++ b/.github/MAINTAINERS
@@ -405,6 +405,7 @@ runtime/indent/json.vim                                     
@elzr
 runtime/indent/jsonc.vim                               @izhakjakov
 runtime/indent/julia.vim                               @carlobaldassi
 runtime/indent/just.vim                                        @pbnj
+runtime/indent/karel.vim                               @KnoP-01
 runtime/indent/kdl.vim                                 @imsnif @jiangyinzuo
 runtime/indent/kotlin.vim                              @udalov
 runtime/indent/krl.vim                                 @KnoP-01
diff --git a/runtime/indent/karel.vim b/runtime/indent/karel.vim
new file mode 100644
index 000000000..991360757
--- /dev/null
+++ b/runtime/indent/karel.vim
@@ -0,0 +1,121 @@
+" Vim indent file
+" Language: Fanuc Karel
+" Maintainer: Patrick Meiser-Knosowski <[email protected]>
+" Version: 1.0.0
+" Last Change: 28. May 2026
+
+" Only load this indent file when no other was loaded.
+if exists("b:did_indent")
+  finish
+endif
+let b:did_indent = 1
+
+setlocal nolisp
+setlocal nocindent
+setlocal nosmartindent
+setlocal autoindent
+setlocal indentexpr=GetKarelIndent()
+setlocal 
indentkeys=!^F,o,O,=~end,0=~else,0=~case,0=~until,0=~const,0=~type,0=~var,0=~begin
+let b:undo_indent = "setlocal lisp< cindent< smartindent< autoindent< 
indentexpr< indentkeys<"
+
+if get(g:,'karelSpaceIndent',1)
+  " Use spaces, not tabs, for indention, 2 is enough. 
+  " More or even tabs would waste valuable space on the teach pendant.
+  setlocal softtabstop=2
+  setlocal shiftwidth=2
+  setlocal expandtab
+  setlocal shiftround
+  let b:undo_indent = b:undo_indent." softtabstop< shiftwidth< expandtab< 
shiftround<"
+endif
+
+" Only define the function once.
+if exists("*GetKarelIndent")
+  finish
+endif
+let s:keepcpo = &cpo
+set cpo&vim
+
+function GetKarelIndent() abort
+
+  let currentLine = getline(v:lnum)
+  if  currentLine =~? ' ^--' && !get(g:, 'karelCommentIndent', 0)
+    " If current line has a -- in column 1, keep zero indent.
+    " This may be useful if code is commented out at the first column.
+    return 0
+  endif
+
+  " Find a non-blank line above the current line.
+  let preNoneBlankLineNum = s:karelPreNoneBlank(v:lnum - 1)
+  if  preNoneBlankLineNum == 0
+    " At the start of the file use zero indent.
+    return 0
+  endif
+
+  let preNoneBlankLine = getline(preNoneBlankLineNum)
+  let ind = indent(preNoneBlankLineNum)
+
+  " Define add 'shiftwidth' pattern
+  let addShiftwidthPattern =           ' ^\s*('
+  let addShiftwidthPattern   ..=               
'if>|while>|for>|using>|condition>|.*<structure>'
+  let addShiftwidthPattern   ..=               '|else>'
+  let addShiftwidthPattern   ..=               '|case>'
+  let addShiftwidthPattern   ..=               '|repeat>'
+  let addShiftwidthPattern   ..=               '|const>'
+  let addShiftwidthPattern   ..=               '|type>'
+  let addShiftwidthPattern   ..=               '|var>'
+  let addShiftwidthPattern   ..=               '|begin>'
+  let addShiftwidthPattern   ..=               '|routine>'
+  if get(g:, 'karelIndentBetweenPrg', 1)
+    let addShiftwidthPattern ..=               '|program>'
+  endif
+  let addShiftwidthPattern   ..=             ')'
+
+  " Define Subtract 'shiftwidth' pattern
+  let subtractShiftwidthPattern =      ' ^\s*('
+  let subtractShiftwidthPattern   ..=          
'end(if|while|for|using|condition|structure)?>'
+  let subtractShiftwidthPattern   ..=          '|else>'
+  let subtractShiftwidthPattern   ..=          '|case>|endselect>'
+  let subtractShiftwidthPattern   ..=          '|until>'
+  let subtractShiftwidthPattern   ..=          '|const>'
+  let subtractShiftwidthPattern   ..=          '|type>'
+  let subtractShiftwidthPattern   ..=          '|var>'
+  let subtractShiftwidthPattern   ..=          '|begin>'
+  let subtractShiftwidthPattern   ..=        ')'
+
+  " Add shiftwidth
+  if preNoneBlankLine =~? addShiftwidthPattern
+    let ind += &sw
+  endif
+
+  " Subtract shiftwidth
+  if currentLine =~? subtractShiftwidthPattern
+    let ind = ind - &sw
+  endif
+
+  " First case after a select gets the indent of the select.
+  if currentLine =~? ' ^\s*case>'  
+        \&& preNoneBlankLine =~? ' ^\s*select>'
+    let ind = ind + &sw
+  endif
+
+  return ind
+endfunction
+
+" This function works almost like prevnonblank() but handles &-headers,
+" comments and continue instructions like blank lines
+function s:karelPreNoneBlank(lnum) abort
+
+  let nPreNoneBlank = prevnonblank(a:lnum)
+
+  while nPreNoneBlank > 0 && getline(nPreNoneBlank) =~? ' ^\s*(\&\w\+|--)'
+    " Previous none blank line irrelevant. Look further aback.
+    let nPreNoneBlank = prevnonblank(nPreNoneBlank - 1)
+  endwhile
+
+  return nPreNoneBlank
+endfunction
+
+let &cpo = s:keepcpo
+unlet s:keepcpo
+
+" vim:sw=2 sts=2 et
diff --git a/runtime/indent/testdir/karel.in b/runtime/indent/testdir/karel.in
new file mode 100644
index 000000000..edee2bdbb
--- /dev/null
+++ b/runtime/indent/testdir/karel.in
@@ -0,0 +1,211 @@
+-- vim: set ft=karel sw=2 :
+
+-- START_INDENT
+-- upper case
+-- test karelIndentBetweenPrg not existing
+-- test karelCommentIndent not existing
+PROGRAM UcKarelPrg
+%CMOSVARS
+TYPE
+Array4OfInt = ARRAY[4] OF integer
+CONST
+Success = 0
+TYPE
+sub_struct = STRUCTURE
+subs_field_1: INTEGER
+subs_field_2: BOOLEAN
+ENDSTRUCTURE
+MyStruct = STRUCTURE
+subs_field_1: INTEGER
+subs_field_2: sub_struct
+ENDSTRUCTURE
+VAR
+i1 :integer
+b1 :boolean
+fhCh :file
+ROUTINE prg1()
+VAR
+i :integer
+BEGIN
+        --
+END prg1
+ROUTINE fcnt1( s :string ) :string
+VAR
+i :integer
+BEGIN
+RETURN ' '
+END fcnt1
+BEGIN
+IF b1 THEN
+        --
+ENDIF
+IF b1 THEN
+        --
+ELSE
+        --
+ENDIF
+WHILE b1 DO
+        --
+ENDWHILE
+FOR i1 = 1 TO 10 DO
+        --
+ENDFOR
+FOR i1 = 10 DOWNTO 1 DO
+        --
+ENDFOR
+USING sub_struct, MyStruct DO
+        --
+ENDUSING
+CONDITION[1]:
+WHEN DIN[1] DO DOUT[1] = TRUE
+ENDCONDITION
+SELECT i1 OF
+CASE (1):
+        --
+CASE (2,3):
+--
+ELSE:
+        --
+ENDSELECT
+END UcKarelPrg
+-- END_INDENT
+
+-- START_INDENT
+-- lower case
+-- INDENT_EXE let g:karelIndentBetweenPrg = 0
+-- INDENT_EXE let g:karelCommentIndent = 0
+program LcKarelPrg
+%CMOSVARS
+type
+Array4OfInt = ARRAY[4] OF integer
+const
+Success = 0
+type
+sub_struct = structure
+subs_field_1: INTEGER
+subs_field_2: BOOLEAN
+endstructure
+MyStruct = structure
+subs_field_1: INTEGER
+subs_field_2: sub_struct
+endstructure
+var
+i1 :integer
+b1 :boolean
+fhCh :file
+routine prg1()
+var
+i :integer
+begin
+        --
+end prg1
+routine fcnt1( s :string ) :string
+var
+i :integer
+begin
+return ' '
+end fcnt1
+begin
+if b1 then
+        --
+endif
+if b1 then
+        --
+else
+        --
+endif
+while b1 do
+        --
+endwhile
+for i1 = 1 to 10 do
+        --
+endfor
+for i1 = 10 downto 1 do
+        --
+endfor
+using sub_struct, MyStruct do
+        --
+endusing
+condition[1]:
+when DIN[1] do DOUT[1] = TRUE
+endcondition
+select i1 of
+case (1):
+        --
+case (2,3):
+--
+else:
+        --
+endselect
+end LcKarelPrg
+-- END_INDENT
+
+-- START_INDENT
+-- mixed case
+-- INDENT_EXE let g:karelIndentBetweenPrg = 1
+-- INDENT_EXE let g:karelCommentIndent = 1
+Program McKarelPrg
+%CMOSVARS
+Type
+Array4OfInt = ARRAY[4] OF integer
+Const
+Success = 0
+Type
+sub_struct = Structure
+subs_field_1: INTEGER
+subs_field_2: BOOLEAN
+EndStructure
+MyStruct = Structure
+subs_field_1: INTEGER
+subs_field_2: sub_struct
+EndStructure
+Var
+i1 :integer
+b1 :boolean
+fhCh :file
+Routine prg1()
+Var
+i :integer
+Begin
+        --
+End prg1
+Routine fcnt1( s :string ) :string
+Var
+i :integer
+Begin
+Return ' '
+End fcnt1
+Begin
+If b1 Then
+        --
+EndIf
+If b1 Then
+        --
+Else
+        --
+EndIf
+While b1 Do
+        --
+EndWhile
+For i1 = 1 To 10 Do
+        --
+EndFor
+For i1 = 10 DownTo 1 Do
+        --
+EndFor
+Using sub_struct, MyStruct Do
+        --
+EndUsing
+Condition[1]:
+When DIN[1] Do DOUT[1] = TRUE
+EndCondition
+Select i1 Of
+Case (1):
+        --
+Case (2,3):
+--
+Else:
+        --
+EndSelect
+End McKarelPrg
+-- END_INDENT
diff --git a/runtime/indent/testdir/karel.ok b/runtime/indent/testdir/karel.ok
new file mode 100644
index 000000000..a7b5e9fa6
--- /dev/null
+++ b/runtime/indent/testdir/karel.ok
@@ -0,0 +1,211 @@
+-- vim: set ft=karel sw=2 :
+
+-- START_INDENT
+-- upper case
+-- test karelIndentBetweenPrg not existing
+-- test karelCommentIndent not existing
+PROGRAM UcKarelPrg
+  %CMOSVARS
+TYPE
+  Array4OfInt = ARRAY[4] OF integer
+CONST
+  Success = 0
+TYPE
+  sub_struct = STRUCTURE
+    subs_field_1: INTEGER
+    subs_field_2: BOOLEAN
+  ENDSTRUCTURE
+  MyStruct = STRUCTURE
+    subs_field_1: INTEGER
+    subs_field_2: sub_struct
+  ENDSTRUCTURE
+VAR
+  i1 :integer
+  b1 :boolean
+  fhCh :file
+  ROUTINE prg1()
+  VAR
+    i :integer
+  BEGIN
+    --
+  END prg1
+  ROUTINE fcnt1( s :string ) :string
+  VAR
+    i :integer
+  BEGIN
+    RETURN ' '
+  END fcnt1
+BEGIN
+  IF b1 THEN
+    --
+  ENDIF
+  IF b1 THEN
+    --
+  ELSE
+    --
+  ENDIF
+  WHILE b1 DO
+    --
+  ENDWHILE
+  FOR i1 = 1 TO 10 DO
+    --
+  ENDFOR
+  FOR i1 = 10 DOWNTO 1 DO
+    --
+  ENDFOR
+  USING sub_struct, MyStruct DO
+    --
+  ENDUSING
+  CONDITION[1]:
+    WHEN DIN[1] DO DOUT[1] = TRUE
+  ENDCONDITION
+  SELECT i1 OF
+  CASE (1):
+    --
+  CASE (2,3):
+--
+  ELSE:
+    --
+  ENDSELECT
+END UcKarelPrg
+-- END_INDENT
+
+-- START_INDENT
+-- lower case
+-- INDENT_EXE let g:karelIndentBetweenPrg = 0
+-- INDENT_EXE let g:karelCommentIndent = 0
+program LcKarelPrg
+%CMOSVARS
+type
+  Array4OfInt = ARRAY[4] OF integer
+const
+  Success = 0
+type
+  sub_struct = structure
+    subs_field_1: INTEGER
+    subs_field_2: BOOLEAN
+  endstructure
+  MyStruct = structure
+    subs_field_1: INTEGER
+    subs_field_2: sub_struct
+  endstructure
+var
+  i1 :integer
+  b1 :boolean
+  fhCh :file
+  routine prg1()
+  var
+    i :integer
+  begin
+    --
+  end prg1
+  routine fcnt1( s :string ) :string
+  var
+    i :integer
+  begin
+    return ' '
+  end fcnt1
+begin
+  if b1 then
+    --
+  endif
+  if b1 then
+    --
+  else
+    --
+  endif
+  while b1 do
+    --
+  endwhile
+  for i1 = 1 to 10 do
+    --
+  endfor
+  for i1 = 10 downto 1 do
+    --
+  endfor
+  using sub_struct, MyStruct do
+    --
+  endusing
+  condition[1]:
+    when DIN[1] do DOUT[1] = TRUE
+  endcondition
+  select i1 of
+  case (1):
+    --
+  case (2,3):
+--
+  else:
+    --
+  endselect
+end LcKarelPrg
+-- END_INDENT
+
+-- START_INDENT
+-- mixed case
+-- INDENT_EXE let g:karelIndentBetweenPrg = 1
+-- INDENT_EXE let g:karelCommentIndent = 1
+Program McKarelPrg
+  %CMOSVARS
+Type
+  Array4OfInt = ARRAY[4] OF integer
+Const
+  Success = 0
+Type
+  sub_struct = Structure
+    subs_field_1: INTEGER
+    subs_field_2: BOOLEAN
+  EndStructure
+  MyStruct = Structure
+    subs_field_1: INTEGER
+    subs_field_2: sub_struct
+  EndStructure
+Var
+  i1 :integer
+  b1 :boolean
+  fhCh :file
+  Routine prg1()
+  Var
+    i :integer
+  Begin
+    --
+  End prg1
+  Routine fcnt1( s :string ) :string
+  Var
+    i :integer
+  Begin
+    Return ' '
+  End fcnt1
+Begin
+  If b1 Then
+    --
+  EndIf
+  If b1 Then
+    --
+  Else
+    --
+  EndIf
+  While b1 Do
+    --
+  EndWhile
+  For i1 = 1 To 10 Do
+    --
+  EndFor
+  For i1 = 10 DownTo 1 Do
+    --
+  EndFor
+  Using sub_struct, MyStruct Do
+    --
+  EndUsing
+  Condition[1]:
+    When DIN[1] Do DOUT[1] = TRUE
+  EndCondition
+  Select i1 Of
+  Case (1):
+    --
+  Case (2,3):
+    --
+  Else:
+    --
+  EndSelect
+End McKarelPrg
+-- END_INDENT

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/vim_dev/E1wT1y8-00D43W-L8%40256bit.org.

Raspunde prin e-mail lui