aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/finddeclarations.pl50
-rwxr-xr-xscripts/gen_vimdoc.py29
-rw-r--r--scripts/genvimvim.lua9
-rw-r--r--scripts/lintcommit.lua205
-rw-r--r--scripts/lua2dox.lua95
-rwxr-xr-xscripts/pvscheck.sh4
-rwxr-xr-xscripts/release.sh15
-rw-r--r--scripts/squash_typos.py223
-rwxr-xr-xscripts/vim-patch.sh24
-rwxr-xr-xscripts/vimpatch.lua4
10 files changed, 519 insertions, 139 deletions
diff --git a/scripts/finddeclarations.pl b/scripts/finddeclarations.pl
deleted file mode 100755
index 1b1a57b9b7..0000000000
--- a/scripts/finddeclarations.pl
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-use warnings;
-
-if ($ARGV[0] eq '--help') {
- print << "EOF";
-Usage:
-
- $0 definitions.c
-EOF
- exit;
-}
-
-my ($cfname, $sfname, $gfname, $cpp) = @ARGV;
-
-my $F;
-
-open $F, "<", $cfname;
-
-my $text = join "", <$F>;
-
-close $F;
-
-my $s = qr/(?>\s*)/aso;
-my $w = qr/(?>\w+)/aso;
-my $argname = qr/$w(?:\[(?>\w+)\])?/aso;
-my $type_regex = qr/(?:$w$s\**$s)+/aso;
-my $arg_regex = qr/(?:$type_regex$s$argname)/aso;
-
-while ($text =~ /
- (?<=\n) # Definition starts at the start of line
- $type_regex # Return type
- $s$w # Function name
- $s\($s
- (?:
- $arg_regex(?:$s,$s$arg_regex)*+
- ($s,$s\.\.\.)? # varargs function
- |void
- )?
- $s\)
- (?:$s FUNC_ATTR_$w(?:\((?>[^)]*)\))?)*+ # Optional attributes
- (?=$s;) # Ending semicolon
- /axsogp) {
- my $match = "${^MATCH}";
- my $s = "${^PREMATCH}";
- $s =~ s/[^\n]++//g;
- my $line = 1 + length $s;
- print "${cfname}:${line}: $match\n";
-}
diff --git a/scripts/gen_vimdoc.py b/scripts/gen_vimdoc.py
index 18a2839702..36e01153f1 100755
--- a/scripts/gen_vimdoc.py
+++ b/scripts/gen_vimdoc.py
@@ -123,11 +123,13 @@ CONFIG = {
'vim.lua',
'shared.lua',
'uri.lua',
+ 'ui.lua',
],
'files': ' '.join([
os.path.join(base_dir, 'src/nvim/lua/vim.lua'),
os.path.join(base_dir, 'runtime/lua/vim/shared.lua'),
os.path.join(base_dir, 'runtime/lua/vim/uri.lua'),
+ os.path.join(base_dir, 'runtime/lua/vim/ui.lua'),
]),
'file_patterns': '*.lua',
'fn_name_prefix': '',
@@ -141,6 +143,7 @@ CONFIG = {
# `shared` functions are exposed on the `vim` module.
'shared': 'vim',
'uri': 'vim',
+ 'ui': 'vim.ui',
},
'append_only': [
'shared.lua',
@@ -187,6 +190,23 @@ CONFIG = {
'module_override': {},
'append_only': [],
},
+ 'diagnostic': {
+ 'mode': 'lua',
+ 'filename': 'diagnostic.txt',
+ 'section_start_token': '*diagnostic-api*',
+ 'section_order': [
+ 'diagnostic.lua',
+ ],
+ 'files': os.path.join(base_dir, 'runtime/lua/vim/diagnostic.lua'),
+ 'file_patterns': '*.lua',
+ 'fn_name_prefix': '',
+ 'section_name': {'diagnostic.lua': 'diagnostic'},
+ 'section_fmt': lambda _: 'Lua module: vim.diagnostic',
+ 'helptag_fmt': lambda _: '*diagnostic-api*',
+ 'fn_helptag_fmt': lambda fstem, name: f'*vim.{fstem}.{name}()*',
+ 'module_override': {},
+ 'append_only': [],
+ },
'treesitter': {
'mode': 'lua',
'filename': 'treesitter.txt',
@@ -197,7 +217,6 @@ CONFIG = {
'query.lua',
'highlighter.lua',
'languagetree.lua',
- 'health.lua',
],
'files': ' '.join([
os.path.join(base_dir, 'runtime/lua/vim/treesitter.lua'),
@@ -950,6 +969,8 @@ def main(config, args):
os.remove(mpack_file)
output_dir = out_dir.format(target=target)
+ log.info("Generating documentation for %s in folder %s",
+ target, output_dir)
debug = args.log_level >= logging.DEBUG
p = subprocess.Popen(
['doxygen', '-'],
@@ -1105,7 +1126,8 @@ def filter_source(filename):
def parse_args():
targets = ', '.join(CONFIG.keys())
- ap = argparse.ArgumentParser()
+ ap = argparse.ArgumentParser(
+ description="Generate helpdoc from source code")
ap.add_argument(
"--log-level", "-l", choices=LOG_LEVELS.keys(),
default=logging.getLevelName(logging.ERROR), help="Set log verbosity"
@@ -1128,7 +1150,7 @@ Doxyfile = textwrap.dedent('''
INPUT_FILTER = "{filter}"
EXCLUDE =
EXCLUDE_SYMLINKS = NO
- EXCLUDE_PATTERNS = */private/*
+ EXCLUDE_PATTERNS = */private/* */health.lua */_*.lua
EXCLUDE_SYMBOLS =
EXTENSION_MAPPING = lua=C
EXTRACT_PRIVATE = NO
@@ -1159,6 +1181,7 @@ if __name__ == "__main__":
print("Setting log level to %s" % args.log_level)
args.log_level = LOG_LEVELS[args.log_level]
log.setLevel(args.log_level)
+ log.addHandler(logging.StreamHandler())
if len(args.source_filter) > 0:
filter_source(args.source_filter[0])
diff --git a/scripts/genvimvim.lua b/scripts/genvimvim.lua
index 2c3701bf0c..ff60b6cce7 100644
--- a/scripts/genvimvim.lua
+++ b/scripts/genvimvim.lua
@@ -1,4 +1,4 @@
-mpack = require('mpack')
+local mpack = require('mpack')
if arg[1] == '--help' then
print('Usage: lua genvimvim.lua src/nvim runtime/syntax/vim/generated.vim')
@@ -52,7 +52,7 @@ local function is_autocmd_cmd(cmd)
or cmd == 'doautoall')
end
-vimcmd_start = 'syn keyword vimCommand contained '
+local vimcmd_start = 'syn keyword vimCommand contained '
w(vimcmd_start)
local prev_cmd = nil
for _, cmd_desc in ipairs(ex_cmds.cmds) do
@@ -123,9 +123,8 @@ end
w('\n\nsyn case match')
local vimfun_start = 'syn keyword vimFuncName contained '
w('\n\n' .. vimfun_start)
-funcs = mpack.unpack(io.open(funcs_file, 'rb'):read("*all"))
-local started = 0
-for name, def in pairs(funcs) do
+local funcs = mpack.unpack(io.open(funcs_file, 'rb'):read("*all"))
+for name, _ in pairs(funcs) do
if name then
if lld.line_length > 850 then
w('\n' .. vimfun_start)
diff --git a/scripts/lintcommit.lua b/scripts/lintcommit.lua
new file mode 100644
index 0000000000..98f9da246c
--- /dev/null
+++ b/scripts/lintcommit.lua
@@ -0,0 +1,205 @@
+-- Usage:
+-- # verbose
+-- nvim -es +"lua require('scripts.lintcommit').main()"
+--
+-- # silent
+-- nvim -es +"lua require('scripts.lintcommit').main({trace=false})"
+--
+-- # self-test
+-- nvim -es +"lua require('scripts.lintcommit')._test()"
+
+local M = {}
+
+local _trace = false
+
+-- Print message
+local function p(s)
+ vim.cmd('set verbose=1')
+ vim.api.nvim_echo({{s, ''}}, false, {})
+ vim.cmd('set verbose=0')
+end
+
+local function die()
+ p('')
+ vim.cmd("cquit 1")
+end
+
+-- Executes and returns the output of `cmd`, or nil on failure.
+--
+-- Prints `cmd` if `trace` is enabled.
+local function run(cmd, or_die)
+ if _trace then
+ p('run: '..vim.inspect(cmd))
+ end
+ local rv = vim.trim(vim.fn.system(cmd)) or ''
+ if vim.v.shell_error ~= 0 then
+ if or_die then
+ p(rv)
+ die()
+ end
+ return nil
+ end
+ return rv
+end
+
+-- Returns nil if the given commit message is valid, or returns a string
+-- message explaining why it is invalid.
+local function validate_commit(commit_message)
+ local commit_split = vim.split(commit_message, ":")
+
+ -- Return true if the type is vim-patch since most of the normal rules don't
+ -- apply.
+ if commit_split[1] == "vim-patch" then
+ return nil
+ end
+
+ -- Check that message isn't too long.
+ if commit_message:len() > 80 then
+ return [[Commit message is too long, a maximum of 80 characters is allowed.]]
+ end
+
+
+ if vim.tbl_count(commit_split) < 2 then
+ return [[Commit message does not include colons.]]
+ end
+
+ local before_colon = commit_split[1]
+ local after_colon = commit_split[2]
+
+ -- Check if commit introduces a breaking change.
+ if vim.endswith(before_colon, "!") then
+ before_colon = before_colon:sub(1, -2)
+ end
+
+ -- Check if type is correct
+ local type = vim.split(before_colon, "%(")[1]
+ local allowed_types = {'build', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'test', 'chore', 'vim-patch'}
+ if not vim.tbl_contains(allowed_types, type) then
+ return string.format(
+ 'Invalid commit type "%s". Allowed types are:\n %s',
+ type,
+ vim.inspect(allowed_types))
+ end
+
+ -- Check if scope is empty
+ if before_colon:match("%(") then
+ local scope = vim.trim(before_colon:match("%((.*)%)"))
+ if scope == '' then
+ return [[Scope can't be empty.]]
+ end
+ end
+
+ -- Check that description doesn't end with a period
+ if vim.endswith(after_colon, ".") then
+ return [[Description ends with a period (".").]]
+ end
+
+ -- Check that description has exactly one whitespace after colon, followed by
+ -- a lowercase letter and then any number of letters.
+ if not string.match(after_colon, '^ %l%a*') then
+ return [[There should be one whitespace after the colon and the first letter should lowercase.]]
+ end
+
+ return nil
+end
+
+function M.main(opt)
+ _trace = not opt or not not opt.trace
+
+ local branch = run({'git', 'branch', '--show-current'}, true)
+ -- TODO(justinmk): check $GITHUB_REF
+ local ancestor = run({'git', 'merge-base', 'origin/master', branch})
+ if not ancestor then
+ ancestor = run({'git', 'merge-base', 'upstream/master', branch})
+ end
+ local commits_str = run({'git', 'rev-list', ancestor..'..'..branch}, true)
+
+ local commits = {}
+ for substring in commits_str:gmatch("%S+") do
+ table.insert(commits, substring)
+ end
+
+ local failed = 0
+ for _, commit_id in ipairs(commits) do
+ local msg = run({'git', 'show', '-s', '--format=%s' , commit_id})
+ if vim.v.shell_error ~= 0 then
+ p('Invalid commit-id: '..commit_id..'"')
+ else
+ local invalid_msg = validate_commit(msg)
+ if invalid_msg then
+ failed = failed + 1
+ p(string.format([[
+Invalid commit message: "%s"
+ Commit: %s
+ %s
+ See also:
+ https://github.com/neovim/neovim/blob/master/CONTRIBUTING.md#commit-messages
+ https://www.conventionalcommits.org/en/v1.0.0/
+]],
+ msg,
+ commit_id,
+ invalid_msg))
+ end
+ end
+ end
+
+ if failed > 0 then
+ die() -- Exit with error.
+ else
+ p('')
+ end
+end
+
+function M._test()
+ -- message:expected_result
+ local test_cases = {
+ ['ci: normal message'] = true,
+ ['build: normal message'] = true,
+ ['docs: normal message'] = true,
+ ['feat: normal message'] = true,
+ ['fix: normal message'] = true,
+ ['perf: normal message'] = true,
+ ['refactor: normal message'] = true,
+ ['revert: normal message'] = true,
+ ['test: normal message'] = true,
+ ['chore: normal message'] = true,
+ ['ci(window): message with scope'] = true,
+ ['ci!: message with breaking change'] = true,
+ ['ci(tui)!: message with scope and breaking change'] = true,
+ ['vim-patch:8.2.3374: Pyret files are not recognized (#15642)'] = true,
+ ['vim-patch:8.1.1195,8.2.{3417,3419}'] = true,
+ [':no type before colon 1'] = false,
+ [' :no type before colon 2'] = false,
+ [' :no type before colon 3'] = false,
+ ['ci(empty description):'] = false,
+ ['ci(whitespace as description): '] = false,
+ ['docs(multiple whitespaces as description): '] = false,
+ ['ci no colon after type'] = false,
+ ['test: extra space after colon'] = false,
+ ['ci: tab after colon'] = false,
+ ['ci:no space after colon'] = false,
+ ['ci :extra space before colon'] = false,
+ ['refactor(): empty scope'] = false,
+ ['ci( ): whitespace as scope'] = false,
+ ['chore: period at end of sentence.'] = false,
+ ['ci: Starting sentence capitalized'] = false,
+ ['unknown: using unknown type'] = false,
+ ['chore: you\'re saying this commit message just goes on and on and on and on and on and on for way too long?'] = false,
+ }
+
+ local failed = 0
+ for message, expected in pairs(test_cases) do
+ local is_valid = (nil == validate_commit(message))
+ if is_valid ~= expected then
+ failed = failed + 1
+ p(string.format('[ FAIL ]: expected=%s, got=%s\n input: "%s"', expected, is_valid, message))
+ end
+ end
+
+ if failed > 0 then
+ die() -- Exit with error.
+ end
+
+end
+
+return M
diff --git a/scripts/lua2dox.lua b/scripts/lua2dox.lua
index 0b36a1e061..d110e34c6a 100644
--- a/scripts/lua2dox.lua
+++ b/scripts/lua2dox.lua
@@ -50,7 +50,7 @@ However I have put in a hack that will insert the "missing" close paren.
The effect is that you will get the function documented, but not with the parameter list you might expect.
]]
-function class(BaseClass, ClassInitialiser)
+local function class(BaseClass, ClassInitialiser)
local newClass = {} -- a new class newClass
if not ClassInitialiser and type(BaseClass) == 'function' then
ClassInitialiser = BaseClass
@@ -68,15 +68,14 @@ function class(BaseClass, ClassInitialiser)
-- expose a constructor which can be called by <classname>(<args>)
local classMetatable = {}
- classMetatable.__call =
- function(class_tbl, ...)
+ classMetatable.__call = function(class_tbl, ...)
local newInstance = {}
setmetatable(newInstance,newClass)
--if init then
-- init(newInstance,...)
if class_tbl.init then
class_tbl.init(newInstance,...)
- else
+ else
-- make sure that any stuff from the base class is initialized!
if BaseClass and BaseClass.init then
BaseClass.init(newInstance, ...)
@@ -85,10 +84,9 @@ function class(BaseClass, ClassInitialiser)
return newInstance
end
newClass.init = ClassInitialiser
- newClass.is_a =
- function(this, klass)
+ newClass.is_a = function(this, klass)
local thisMetatable = getmetatable(this)
- while thisMetatable do
+ while thisMetatable do
if thisMetatable == klass then
return true
end
@@ -102,12 +100,13 @@ end
--! \class TCore_Clock
--! \brief a clock
-TCore_Clock = class()
+local TCore_Clock = class()
--! \brief get the current time
function TCore_Clock.GetTimeNow()
- if os.gettimeofday then
- return os.gettimeofday()
+ local gettimeofday = os.gettimeofday -- luacheck: ignore 143 Accessing an undefined field of a global variable.
+ if gettimeofday then
+ return gettimeofday()
else
return os.time()
end
@@ -134,20 +133,15 @@ function TCore_Clock.getTimeStamp(this,T0)
end
---! \brief io to console
---!
---! pseudo class (no methods, just to keep documentation tidy)
-TCore_IO = class()
---
--! \brief write to stdout
-function TCore_IO_write(Str)
+local function TCore_IO_write(Str)
if (Str) then
io.write(Str)
end
end
--! \brief write to stdout
-function TCore_IO_writeln(Str)
+local function TCore_IO_writeln(Str)
if (Str) then
io.write(Str)
end
@@ -156,16 +150,16 @@ end
--! \brief trims a string
-function string_trim(Str)
+local function string_trim(Str)
return Str:match("^%s*(.-)%s*$")
end
--! \brief split a string
---!
+--!
--! \param Str
--! \param Pattern
--! \returns table of string fragments
-function string_split(Str, Pattern)
+local function string_split(Str, Pattern)
local splitStr = {}
local fpat = "(.-)" .. Pattern
local last_end = 1
@@ -187,7 +181,7 @@ end
--! \class TCore_Commandline
--! \brief reads/parses commandline
-TCore_Commandline = class()
+local TCore_Commandline = class()
--! \brief constructor
function TCore_Commandline.init(this)
@@ -207,29 +201,21 @@ end
-------------------------------
--! \brief file buffer
---!
+--!
--! an input file buffer
-TStream_Read = class()
+local TStream_Read = class()
--! \brief get contents of file
---!
+--!
--! \param Filename name of file to read (or nil == stdin)
function TStream_Read.getContents(this,Filename)
+ assert(Filename)
-- get lines from file
- local filecontents
- if Filename then
- -- syphon lines to our table
- --TCore_Debug_show_var('Filename',Filename)
- filecontents={}
- for line in io.lines(Filename) do
- table.insert(filecontents,line)
- end
- else
- -- get stuff from stdin as a long string (with crlfs etc)
- filecontents=io.read('*a')
- -- make it a table of lines
- filecontents = TString_split(filecontents,'[\n]') -- note this only works for unix files.
- Filename = 'stdin'
+ -- syphon lines to our table
+ --TCore_Debug_show_var('Filename',Filename)
+ local filecontents={}
+ for line in io.lines(Filename) do
+ table.insert(filecontents,line)
end
if filecontents then
@@ -278,7 +264,7 @@ function TStream_Read.eof(this)
end
--! \brief output stream
-TStream_Write = class()
+local TStream_Write = class()
--! \brief constructor
function TStream_Write.init(this)
@@ -286,17 +272,17 @@ function TStream_Write.init(this)
end
--! \brief write immediately
-function TStream_Write.write(this,Str)
+function TStream_Write.write(_,Str)
TCore_IO_write(Str)
end
--! \brief write immediately
-function TStream_Write.writeln(this,Str)
+function TStream_Write.writeln(_,Str)
TCore_IO_writeln(Str)
end
--! \brief write immediately
-function TStream_Write.writelnComment(this,Str)
+function TStream_Write.writelnComment(_,Str)
TCore_IO_write('// ZZ: ')
TCore_IO_writeln(Str)
end
@@ -311,14 +297,14 @@ end
--! \brief outout tail lines
function TStream_Write.write_tailLines(this)
- for k,line in ipairs(this.tailLine) do
+ for _,line in ipairs(this.tailLine) do
TCore_IO_writeln(line)
end
TCore_IO_write('// Lua2DoX new eof')
end
--! \brief input filter
-TLua2DoX_filter = class()
+local TLua2DoX_filter = class()
--! \brief allow us to do errormessages
function TLua2DoX_filter.warning(this,Line,LineNo,Legend)
@@ -371,12 +357,12 @@ local function checkComment4fn(Fn_magic,MagicLines)
local macro,tail
- for k,line in ipairs(magicLines) do
+ for _, line in ipairs(magicLines) do
macro,tail = getMagicDirective(line)
if macro == 'fn' then
fn_magic = tail
-- TCore_IO_writeln('// found fn "' .. fn_magic .. '"')
- else
+ --else
--TCore_IO_writeln('// not found fn "' .. line .. '"')
end
end
@@ -385,8 +371,6 @@ local function checkComment4fn(Fn_magic,MagicLines)
end
--! \brief run the filter
function TLua2DoX_filter.readfile(this,AppStamp,Filename)
- local err
-
local inStream = TStream_Read()
local outStream = TStream_Write()
this.outStream = outStream -- save to this obj
@@ -401,8 +385,9 @@ function TLua2DoX_filter.readfile(this,AppStamp,Filename)
outStream:writelnTail('// #######################')
outStream:writelnTail()
- local state, offset = '', 0
- while not (err or inStream:eof()) do
+ local state = '' -- luacheck: ignore 231 variable is set but never accessed.
+ local offset = 0
+ while not (inStream:eof()) do
line = string_trim(inStream:getLine())
-- TCore_Debug_show_var('inStream',inStream)
-- TCore_Debug_show_var('line',line )
@@ -427,7 +412,7 @@ function TLua2DoX_filter.readfile(this,AppStamp,Filename)
line = string.sub(line,5) -- nibble head
local comment = ''
local closeSquare,hitend,thisComment
- while (not err) and (not hitend) and (not inStream:eof()) do
+ while (not hitend) and (not inStream:eof()) do
closeSquare = string.find(line,']]')
if not closeSquare then -- need to look on another line
thisComment = line .. '\n'
@@ -544,7 +529,7 @@ function TLua2DoX_filter.readfile(this,AppStamp,Filename)
end
--! \brief this application
-TApp = class()
+local TApp = class()
--! \brief constructor
function TApp.init(this)
@@ -556,16 +541,16 @@ function TApp.init(this)
end
function TApp.getRunStamp(this)
- return this.name .. ' (' .. this.version .. ') '
+ return this.name .. ' (' .. this.version .. ') '
.. this.timestamp
end
function TApp.getVersion(this)
- return this.name .. ' (' .. this.version .. ') '
+ return this.name .. ' (' .. this.version .. ') '
end
function TApp.getCopyright(this)
- return this.copyright
+ return this.copyright
end
local This_app = TApp()
diff --git a/scripts/pvscheck.sh b/scripts/pvscheck.sh
index f3371b485e..904ff81700 100755
--- a/scripts/pvscheck.sh
+++ b/scripts/pvscheck.sh
@@ -373,13 +373,13 @@ run_analysis() {(
analyze \
--lic-file PVS-Studio.lic \
--threads "$(get_jobs_num)" \
- --exclude-path src/nvim/xdiff \
+ --exclude-path src/xdiff \
--output-file PVS-studio.log \
--file build/compile_commands.json \
--sourcetree-root . || true
rm -rf PVS-studio.{xml,err,tsk,html.d}
- local plog_args="PVS-studio.log --srcRoot . --excludedCodes V011"
+ local plog_args="PVS-studio.log --srcRoot . --excludedCodes V011,V1042,V1051,V1074"
plog-converter $plog_args --renderTypes xml --output PVS-studio.xml
plog-converter $plog_args --renderTypes errorfile --output PVS-studio.err
plog-converter $plog_args --renderTypes tasklist --output PVS-studio.tsk
diff --git a/scripts/release.sh b/scripts/release.sh
index 4d1484b77a..4ec959d697 100755
--- a/scripts/release.sh
+++ b/scripts/release.sh
@@ -12,6 +12,7 @@
# - CMakeLists.txt: Unset NVIM_VERSION_PRERELEASE
# - CMakeLists.txt: Unset NVIM_API_PRERELEASE
# - Create test/functional/fixtures/api_level_N.mpack
+# - Add date and version to runtime/nvim.appdata.xml
# - Tag the commit.
# Create the "version bump" commit:
# - CMakeLists.txt: Set NVIM_VERSION_PRERELEASE to "-dev"
@@ -62,6 +63,10 @@ _do_release_commit() {
git add test/functional/fixtures/api_level_$__API_LEVEL.mpack
fi
+ $__sed -i.bk 's,(<releases>),\1\
+ <release date="'"${__DATE}"'" version="'"${__VERSION}"'"/>,' runtime/nvim.appdata.xml
+ git add runtime/nvim.appdata.xml
+
if ! test "$ARG1" = '--use-current-commit' ; then
echo "Building changelog since ${__LAST_TAG}..."
@@ -75,14 +80,12 @@ _do_release_commit() {
_do_bump_commit() {
$__sed -i.bk 's/(NVIM_VERSION_PRERELEASE) ""/\1 "-dev"/' CMakeLists.txt
$__sed -i.bk 's/set\((NVIM_VERSION_PATCH) [[:digit:]]/set(\1 ?/' CMakeLists.txt
- $__sed -i.bk 's,(<releases>),\1\
- <release date="'"${__DATE}"'" version="xxx"/>,' runtime/nvim.appdata.xml
rm CMakeLists.txt.bk
rm runtime/nvim.appdata.xml.bk
nvim +'/NVIM_VERSION' +1new +'exe "norm! iUpdate version numbers!!!"' \
- -O CMakeLists.txt runtime/nvim.appdata.xml
+ -O CMakeLists.txt
- git add CMakeLists.txt runtime/nvim.appdata.xml
+ git add CMakeLists.txt
git commit -m "$__BUMP_MSG"
}
@@ -92,11 +95,7 @@ fi
_do_bump_commit
echo "
Next steps:
- - Update runtime/nvim.appdata.xml on _master_
- Run tests/CI (version_spec.lua)!
- Push the tag:
git push --follow-tags
- - Update the 'stable' tag:
- git push --force upstream HEAD^:refs/tags/stable
- git fetch --tags
- Update website: index.html"
diff --git a/scripts/squash_typos.py b/scripts/squash_typos.py
new file mode 100644
index 0000000000..26be6010a2
--- /dev/null
+++ b/scripts/squash_typos.py
@@ -0,0 +1,223 @@
+#!/usr/bin/env python
+"""
+
+This script squashes a PR tagged with the "typo" label into a single, dedicated
+"squash PR".
+
+"""
+
+import subprocess
+import sys
+import os
+
+
+def get_authors_and_emails_from_pr():
+ """
+
+ Return all contributing authors and their emails for the PR on current branch.
+ This includes co-authors, meaning that if two authors are credited for a
+ single commit, which is possible with GitHub, then both will get credited.
+
+ """
+
+ # Get a list of all authors involved in the pull request (including co-authors).
+ authors = subprocess.check_output(
+ ["gh", "pr", "view", "--json", "commits", "--jq", ".[][].authors.[].name"],
+ text=True,
+ ).splitlines()
+
+ # Get a list of emails of the aforementioned authors.
+ emails = subprocess.check_output(
+ ["gh", "pr", "view", "--json", "commits", "--jq", ".[][].authors.[].email"],
+ text=True,
+ ).splitlines()
+
+ authors_and_emails_unique = {
+ (author, mail) for author, mail in zip(authors, emails)
+ }
+
+ return sorted(authors_and_emails_unique)
+
+
+def rebase_squash_branch_onto_pr():
+ """
+
+ Rebase current branch onto the PR.
+
+ """
+
+ # Check out the pull request.
+ subprocess.call(["gh", "pr", "checkout", os.environ["PR_NUMBER"]])
+
+ # Rebase onto master
+ default_branch = f"{os.environ['GITHUB_BASE_REF']}"
+ subprocess.check_call(["git", "rebase", default_branch])
+
+ # Change back to the original branch.
+ subprocess.call(["git", "switch", "-"])
+
+ # Rebase onto the pull request, aka include the commits in the pull request
+ # in the current branch. Abort with error message if rebase fails.
+
+ try:
+ subprocess.check_call(["git", "rebase", "-"])
+ except subprocess.CalledProcessError:
+ subprocess.call(["git", "rebase", "--abort"])
+ squash_url = subprocess.check_output(
+ ["gh", "pr", "view", "--json", "url", "--jq", ".url"], text=True
+ ).strip()
+
+ subprocess.call(
+ [
+ "gh",
+ "pr",
+ "comment",
+ os.environ["PR_NUMBER"],
+ "--body",
+ f"Your edit conflicts with an already scheduled fix \
+ ({squash_url}). Please check that batch PR whether your fix is \
+ already included; if not, then please wait until the batch PR \
+ is merged and then rebase your PR on top of master.",
+ ]
+ )
+
+ sys.exit(
+ f"\n\nERROR: Your edit conflicts with an already scheduled fix \
+{squash_url} \n\n"
+ )
+
+
+def rebase_squash_branch_onto_master():
+ """
+
+ Rebase current branch onto the master i.e. make sure current branch is up
+ to date. Abort on error.
+
+ """
+
+ default_branch = f"{os.environ['GITHUB_BASE_REF']}"
+ subprocess.check_call(["git", "rebase", default_branch])
+
+
+def squash_all_commits():
+ """
+
+ Squash all commits on the PR into a single commit. Credit all authors by
+ name and email.
+
+ """
+
+ default_branch = f"{os.environ['GITHUB_BASE_REF']}"
+ subprocess.call(["git", "reset", "--soft", default_branch])
+
+ authors_and_emails = get_authors_and_emails_from_pr()
+ commit_message_coauthors = "\n" + "\n".join(
+ [f"Co-authored-by: {i[0]} <{i[1]}>" for i in authors_and_emails]
+ )
+ subprocess.call(
+ ["git", "commit", "-m", "chore: typo fixes", "-m", commit_message_coauthors]
+ )
+
+
+def force_push(branch):
+ """
+
+ Like the name implies, force push <branch>.
+
+ """
+
+ gh_actor = os.environ["GITHUB_ACTOR"]
+ gh_token = os.environ["GITHUB_TOKEN"]
+ gh_repo = os.environ["GITHUB_REPOSITORY"]
+ subprocess.call(
+ [
+ "git",
+ "push",
+ "--force",
+ f"https://{gh_actor}:{gh_token}@github.com/{gh_repo}",
+ branch,
+ ]
+ )
+
+
+def checkout_branch(branch):
+ """
+
+ Create and checkout <branch>. Check if branch exists on remote, if so then
+ sync local branch to remote.
+
+ Return True if remote branch exists, else False.
+
+ """
+
+ # FIXME I'm not sure why the local branch isn't tracking the remote branch
+ # automatically. This works but I'm pretty sure it can be done in a more
+ # "elegant" fashion
+
+ show_ref_output = subprocess.check_output(["git", "show-ref"], text=True).strip()
+
+ if branch in show_ref_output:
+ subprocess.call(["git", "checkout", "-b", branch, f"origin/{branch}"])
+ return True
+
+ subprocess.call(["git", "checkout", "-b", branch])
+ return False
+
+
+def get_all_pr_urls(squash_branch_exists):
+ """
+
+ Return a list of URLs for the pull requests with the typo fixes. If a
+ squash branch exists then extract the URLs from the body text.
+
+ """
+
+ all_pr_urls = ""
+ if squash_branch_exists:
+ all_pr_urls += subprocess.check_output(
+ ["gh", "pr", "view", "--json", "body", "--jq", ".body"], text=True
+ )
+
+ all_pr_urls += subprocess.check_output(
+ ["gh", "pr", "view", os.environ["PR_NUMBER"], "--json", "url", "--jq", ".url"],
+ text=True,
+ ).strip()
+
+ return all_pr_urls
+
+
+def main():
+ squash_branch = "marvim/squash-typos"
+
+ squash_branch_exists = checkout_branch(squash_branch)
+
+ rebase_squash_branch_onto_master()
+ force_push(squash_branch)
+
+ rebase_squash_branch_onto_pr()
+ force_push(squash_branch)
+
+ subprocess.call(
+ [
+ "gh",
+ "pr",
+ "create",
+ "--fill",
+ "--head",
+ squash_branch,
+ "--title",
+ "chore: typo fixes (automated)",
+ ]
+ )
+
+ squash_all_commits()
+ force_push(squash_branch)
+
+ all_pr_urls = get_all_pr_urls(squash_branch_exists)
+ subprocess.call(["gh", "pr", "edit", "--add-label", "typo", "--body", all_pr_urls])
+
+ subprocess.call(["gh", "pr", "close", os.environ["PR_NUMBER"]])
+
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh
index 4fd9711619..f4b817dfff 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -190,7 +190,7 @@ preprocess_patch() {
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/src/\S*\<\%(testdir/\)\@<!\%('"${na_src}"'\)@norm! d/\v(^diff)|%$ ' +w +q "$file"
# Remove unwanted Vim doc files.
- local na_doc='channel\.txt\|netbeans\.txt\|os_\w\+\.txt\|term\.txt\|todo\.txt\|version\d\.txt\|sponsor\.txt\|intro\.txt\|tags'
+ local na_doc='channel\.txt\|netbeans\.txt\|os_\w\+\.txt\|term\.txt\|todo\.txt\|version\d\.txt\|vim9\.txt\|sponsor\.txt\|intro\.txt\|tags'
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/runtime/doc/\<\%('"${na_doc}"'\)\>@norm! d/\v(^diff)|%$ ' +w +q "$file"
# Remove "Last change ..." changes in doc files.
@@ -326,12 +326,14 @@ stage_patch() {
return $ret
}
-hub_pr() {
- hub pull-request -m "$1"
+gh_pr() {
+ gh pr create --title "$1" --body "$2"
}
git_hub_pr() {
- git hub pull new -m "$1"
+ local pr_message
+ pr_message="$(printf '%s\n\n%s\n' "$1" "$2")"
+ git hub pull new -m "${pr_message}"
}
# shellcheck disable=SC2015
@@ -341,14 +343,14 @@ submit_pr() {
local push_first
push_first=1
local submit_fn
- if check_executable hub; then
- submit_fn="hub_pr"
+ if check_executable gh; then
+ submit_fn="gh_pr"
elif check_executable git-hub; then
push_first=0
submit_fn="git_hub_pr"
else
- >&2 echo "${BASENAME}: 'hub' or 'git-hub' not found in PATH or not executable."
- >&2 echo " Get it here: https://hub.github.com/"
+ >&2 echo "${BASENAME}: 'gh' or 'git-hub' not found in PATH or not executable."
+ >&2 echo " Get it here: https://cli.github.com/"
exit 1
fi
@@ -371,9 +373,7 @@ submit_pr() {
patches=(${patches[@]//vim-patch:}) # Remove 'vim-patch:' prefix for each item in array.
local pr_title="${patches[*]}" # Create space-separated string from array.
pr_title="${pr_title// /,}" # Replace spaces with commas.
-
- local pr_message
- pr_message="$(printf 'vim-patch:%s\n\n%s\n' "${pr_title#,}" "${pr_body}")"
+ pr_title="$(printf 'vim-patch:%s' "${pr_title#,}")"
if [[ $push_first -ne 0 ]]; then
echo "Pushing to 'origin/${checked_out_branch}'."
@@ -385,7 +385,7 @@ submit_pr() {
fi
echo "Creating pull request."
- output="$(${submit_fn} "${pr_message}" 2>&1)" &&
+ output="$(${submit_fn} "${pr_title}" "${pr_body}" 2>&1)" &&
msg_ok "${output}" ||
(msg_err "${output}"; false)
diff --git a/scripts/vimpatch.lua b/scripts/vimpatch.lua
index 0924f3d718..11eb285462 100755
--- a/scripts/vimpatch.lua
+++ b/scripts/vimpatch.lua
@@ -5,10 +5,6 @@
local nvim = vim.api
-local function pprint(o)
- print(nvim.nvim_call_function('string', { o }))
-end
-
local function systemlist(...)
local rv = nvim.nvim_call_function('systemlist', ...)
local err = nvim.nvim_get_vvar('shell_error')