From f58d24040a32e5f28f57048657c40e302894b314 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 14 Mar 2026 09:42:10 +0800 Subject: [PATCH] vim-patch:9.2.0155: filetype: ObjectScript are not recognized (#38288) Problem: filetype: ObjectScript are not recognized Solution: Add ObjectScript filetype detection for *.cls files (Hannah Kimura)). Reference: https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCOS_intro closes: vim/vim#19668 https://github.com/vim/vim/commit/b11c8efbe6981076194e00323737780330cfd0a1 Co-authored-by: Hannah --- runtime/lua/vim/filetype.lua | 9 ++++---- runtime/lua/vim/filetype/detect.lua | 23 ++++++++++++++++++-- src/nvim/eval/executor.c | 2 +- test/old/testdir/test_filetype.vim | 33 +++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 7 deletions(-) diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 20cfc97eea..846a76ab19 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -92,14 +92,15 @@ end --- ---@param bufnr integer The buffer to get the line from ---@param start_lnum integer The line number of the first line to start from (inclusive, 1-based) ----@return string|nil The first non-blank line if found or `nil` otherwise +---@return string|nil line The first non-blank line if found or `nil` otherwise +---@return integer|nil lnum The line number of the first non-blank line or `nil` function M._nextnonblank(bufnr, start_lnum) - for _, line in ipairs(M._getlines(bufnr, start_lnum, -1)) do + for off, line in ipairs(M._getlines(bufnr, start_lnum, -1)) do if not line:find('^%s*$') then - return line + return line, start_lnum + off - 1 end end - return nil + return nil, nil end do diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index 0ac39ba155..6f81e92150 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -252,6 +252,7 @@ function M.class(_, bufnr) end end +--- Determines whether a *.cls file is ObjectScript, TeX, Rexx, Visual Basic, or Smalltalk. --- @type vim.filetype.mapfn function M.cls(_, bufnr) if vim.g.filetype_cls then @@ -264,8 +265,26 @@ function M.cls(_, bufnr) return 'vb' end - local nonblank1 = nextnonblank(bufnr, 1) - if nonblank1 and nonblank1:find('^[%%\\]') then + local nonblank1, lnum = nextnonblank(bufnr, 1) + local line = nonblank1 + while line do + if matchregex(line, [[\c^\s*\%(import\|include\|includegenerator\)\>]]) then + line, lnum = nextnonblank(bufnr, lnum + 1) + else + nonblank1 = line + break + end + end + + if + nonblank1 + and matchregex( + nonblank1, + [[\c^\s*class\>\s\+[%A-Za-z][%A-Za-z0-9_.]*\%(\s\+extends\>\|\s*\[\|\s*{\|$\)]] + ) + then + return 'objectscript' + elseif nonblank1 and nonblank1:find('^[%%\\]') then return 'tex' elseif nonblank1 and findany(nonblank1, { '^%s*/%*', '^%s*::%w' }) then return 'rexx' diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c index d8d10992a6..d0b9c3db15 100644 --- a/src/nvim/eval/executor.c +++ b/src/nvim/eval/executor.c @@ -130,12 +130,12 @@ static int tv_op_string(typval_T *tv1, const typval_T *tv2, const char *op) } char numbuf[NUMBUFLEN]; + // str .= str const char *s2 = tv_get_string_buf(tv2, numbuf); if (grow_string_tv(tv1, s2) == OK) { return OK; } - // str .= str const char *tvs = tv_get_string(tv1); char *const s = concat_str(tvs, s2); tv_clear(tv1); diff --git a/test/old/testdir/test_filetype.vim b/test/old/testdir/test_filetype.vim index 30b311ee8e..59f5ea2139 100644 --- a/test/old/testdir/test_filetype.vim +++ b/test/old/testdir/test_filetype.vim @@ -2548,6 +2548,39 @@ func Test_cls_file() bwipe! unlet g:filetype_cls + let g:filetype_cls = 'objectscript' + split Xfile.cls + call assert_equal('objectscript', &filetype) + bwipe! + unlet g:filetype_cls + + " ObjectScript + + call writefile(['Class User.Person Extends (%Persistent, %Populate)'], 'Xfile.cls') + split Xfile.cls + call assert_equal('objectscript', &filetype) + bwipe! + + call writefile(['Import MyApp.Utils', 'Class User.Person Extends %Persistent'], 'Xfile.cls') + split Xfile.cls + call assert_equal('objectscript', &filetype) + bwipe! + + call writefile(['Include MyMacros', 'Class User.Person Extends %Persistent'], 'Xfile.cls') + split Xfile.cls + call assert_equal('objectscript', &filetype) + bwipe! + + call writefile(['IncludeGenerator MyGen', 'Class User.Person Extends %Persistent'], 'Xfile.cls') + split Xfile.cls + call assert_equal('objectscript', &filetype) + bwipe! + + call writefile(['Import MyApp.Utils', 'Include MyMacros', 'IncludeGenerator MyGen', 'Class User.Person Extends %Persistent'], 'Xfile.cls') + split Xfile.cls + call assert_equal('objectscript', &filetype) + bwipe! + " TeX call writefile(['%'], 'Xfile.cls')