runtime(karel): Add indent plugin for Karel
Commit:
https://github.com/vim/vim/commit/f31407f9fa7e38ba63bc0c7abe532db98a21532b
Author: Patrick Meiser-Knosowski <
knos...@graeffrobotics.de>
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 <
knos...@graeffrobotics.de>
Signed-off-by: Christian Brabandt <
c...@256bit.org>
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 <
knos...@graeffrobotics.de>
+" 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