diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 65fb450c..4a276bf5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,13 +9,15 @@ on: inputs: version: description: Release Version - default: v2.1.3 + default: v2.1.4 required: true jobs: release: name: Create Release runs-on: ubuntu-latest + permissions: + contents: write outputs: upload_url: ${{ steps.create_release.outputs.upload_url }} version: ${{ steps.tag.outputs.version }} diff --git a/LICENSE b/LICENSE index 387fd09d..5d3dd47b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,6 @@ -Copyright (c) 2020-present Lite XL Team +Copyright (c) 2020 rxi +Copyright (c) 2020-2022 Francesco Abbate +Copyright (c) 2022-present Lite XL Team Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/changelog.md b/changelog.md index a488016d..3283bdf1 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,58 @@ # Changes Log +## [2.1.4] - 2024-04-16 + +This release addresses severe bugs not found in previous releases, +and improves the usability of the program. + +### Features + +* Add `.pyi` extension to `language_python`. + ([#1728](https://github.com/lite-xl/lite-xl/pull/1728)) + +* Improve autocomplete suggestions box behavior with long text + ([#1734](https://github.com/lite-xl/lite-xl/pull/1734)) + +* Improve `CommandView` and autocomplete scroll behavior + ([#1732](https://github.com/lite-xl/lite-xl/pull/1732)) + +* Add `from` symbol to support ESM + ([#1754](https://github.com/lite-xl/lite-xl/pull/1754)) + +* Add Arduino syntax highlighting support in `language_cpp` + ([#1767](https://github.com/lite-xl/lite-xl/pull/1767)) + +* Skip patterns matching nothing in tokenizer + ([#1743](https://github.com/lite-xl/lite-xl/pull/1743)) + +### Fixes + +* Fix uninitialized variables in `src/api/process.c` + ([#1719](https://github.com/lite-xl/lite-xl/pull/1719)) + +* Fix `language_js` regex/comment distinction + ([#1731](https://github.com/lite-xl/lite-xl/pull/1731)) + +* Fix compilation on non-MINGW64 platforms + ([#1739](https://github.com/lite-xl/lite-xl/pull/1739)) + +* Limit `language_js` regex avoidance to numbers, and fix starting `/*` comments + ([#1744](https://github.com/lite-xl/lite-xl/pull/1744)) + +* Fix `buffer_size` in `g_read` for Windows + ([#1722](https://github.com/lite-xl/lite-xl/pull/1722)) + +* Fix missing permission for creating releases + ([#1770](https://github.com/lite-xl/lite-xl/pull/1770)) + +### Other Changes + +* Rectify LICENSE dates and owners + ([#1748](https://github.com/lite-xl/lite-xl/pull/1748)) + +* Fix some typos in `core.init` + ([#1755](https://github.com/lite-xl/lite-xl/pull/1755)) + ## [2.1.3] - 2024-01-29 This release addresses severe bugs not found in previous releases. @@ -1451,6 +1504,7 @@ A new global variable `USERDIR` is exposed to point to the user's directory. - subpixel font rendering with gamma correction +[2.1.4]: https://github.com/lite-xl/lite-xl/releases/tag/v2.1.4 [2.1.3]: https://github.com/lite-xl/lite-xl/releases/tag/v2.1.3 [2.1.2]: https://github.com/lite-xl/lite-xl/releases/tag/v2.1.2 [2.1.1]: https://github.com/lite-xl/lite-xl/releases/tag/v2.1.1 diff --git a/data/core/commandview.lua b/data/core/commandview.lua index 1f388678..305936b9 100644 --- a/data/core/commandview.lua +++ b/data/core/commandview.lua @@ -50,6 +50,7 @@ local default_state = { function CommandView:new() CommandView.super.new(self, SingleLineDoc()) self.suggestion_idx = 1 + self.suggestions_offset = 1 self.suggestions = {} self.suggestions_height = 0 self.last_change_id = 0 @@ -123,6 +124,24 @@ function CommandView:move_suggestion_idx(dir) end end + local function get_suggestions_offset() + local max_visible = math.min(max_suggestions, #self.suggestions) + if dir > 0 then + if self.suggestions_offset + max_visible < self.suggestion_idx + 1 then + return self.suggestion_idx - max_visible + 1 + elseif self.suggestions_offset > self.suggestion_idx then + return self.suggestion_idx + end + else + if self.suggestions_offset > self.suggestion_idx then + return self.suggestion_idx + elseif self.suggestions_offset + max_visible < self.suggestion_idx + 1 then + return self.suggestion_idx - max_visible + 1 + end + end + return self.suggestions_offset + end + if self.state.show_suggestions then local n = self.suggestion_idx + dir self.suggestion_idx = overflow_suggestion_idx(n, #self.suggestions) @@ -146,6 +165,8 @@ function CommandView:move_suggestion_idx(dir) self.last_change_id = self.doc:get_change_id() self.state.suggest(self:get_text()) end + + self.suggestions_offset = get_suggestions_offset() end @@ -256,6 +277,7 @@ function CommandView:update_suggestions() end self.suggestions = res self.suggestion_idx = 1 + self.suggestions_offset = 1 end @@ -299,7 +321,7 @@ function CommandView:update() self:move_towards("suggestions_height", dest, nil, "commandview") -- update suggestion cursor offset - local dest = math.min(self.suggestion_idx, max_suggestions) * self:get_suggestion_line_height() + local dest = (self.suggestion_idx - self.suggestions_offset + 1) * self:get_suggestion_line_height() self:move_towards("selection_offset", dest, nil, "commandview") -- update size based on whether this is the active_view @@ -335,6 +357,7 @@ local function draw_suggestions_box(self) local h = math.ceil(self.suggestions_height) local rx, ry, rw, rh = self.position.x, self.position.y - h - dh, self.size.x, h + core.push_clip_rect(rx, ry, rw, rh) -- draw suggestions background if #self.suggestions > 0 then renderer.draw_rect(rx, ry, rw, rh, style.background3) @@ -344,14 +367,12 @@ local function draw_suggestions_box(self) end -- draw suggestion text - local offset = math.max(self.suggestion_idx - max_suggestions, 0) - local last = math.min(offset + max_suggestions, #self.suggestions) - core.push_clip_rect(rx, ry, rw, rh) - local first = 1 + offset + local first = math.max(self.suggestions_offset, 1) + local last = math.min(self.suggestions_offset + max_suggestions, #self.suggestions) for i=first, last do local item = self.suggestions[i] local color = (i == self.suggestion_idx) and style.accent or style.text - local y = self.position.y - (i - offset) * lh - dh + local y = self.position.y - (i - first + 1) * lh - dh common.draw_text(self:get_font(), color, item.text, nil, x, y, 0, lh) if item.info then diff --git a/data/core/init.lua b/data/core/init.lua index b34376da..3facdacc 100644 --- a/data/core/init.lua +++ b/data/core/init.lua @@ -250,7 +250,6 @@ function core.add_project_directory(path) -- will be simply the name of the directory, without its path. -- The field item.topdir will identify it as a top level directory. path = common.normalize_volume(path) - local topdir = { name = path, item = {filename = common.basename(path), type = "dir", topdir = true}, @@ -573,22 +572,22 @@ local config = require "core.config" -- -- Here some examples: -- --- "^%." match any file of directory whose basename begins with a dot. +-- "^%." matches any file of directory whose basename begins with a dot. -- --- When there is an '/' or a '/$' at the end the pattern it will only match +-- When there is an '/' or a '/$' at the end, the pattern will only match -- directories. When using such a pattern a final '/' will be added to the name -- of any directory entry before checking if it matches. -- -- "^%.git/" matches any directory named ".git" anywhere in the project. -- --- If a "/" appears anywhere in the pattern except if it appears at the end or --- is immediately followed by a '$' then the pattern will be applied to the full +-- If a "/" appears anywhere in the pattern (except when it appears at the end or +-- is immediately followed by a '$'), then the pattern will be applied to the full -- path of the file or directory. An initial "/" will be prepended to the file's -- or directory's path to indicate the project's root. -- -- "^/node_modules/" will match a directory named "node_modules" at the project's root. --- "^/build.*/" match any top level directory whose name begins with "build" --- "^/subprojects/.+/" match any directory inside a top-level folder named "subprojects". +-- "^/build.*/" will match any top level directory whose name begins with "build". +-- "^/subprojects/.+/" will match any directory inside a top-level folder named "subprojects". -- You may activate some plugins on a per-project basis to override the user's settings. -- config.plugins.trimwitespace = true diff --git a/data/core/start.lua b/data/core/start.lua index 7b0f553e..4168a16e 100644 --- a/data/core/start.lua +++ b/data/core/start.lua @@ -1,5 +1,5 @@ -- this file is used by lite-xl to setup the Lua environment when starting -VERSION = "2.1.3r2" +VERSION = "2.1.4r1" MOD_VERSION = "3" SCALE = tonumber(os.getenv("LITE_SCALE") or os.getenv("GDK_SCALE") or os.getenv("QT_SCALE_FACTOR")) or 1 @@ -12,7 +12,6 @@ else local prefix = os.getenv('LITE_PREFIX') or EXEDIR:match("^(.+)[/\\]bin$") DATADIR = prefix and (prefix .. PATHSEP .. 'share' .. PATHSEP .. 'lite-xl') or (EXEDIR .. PATHSEP .. 'data') end - USERDIR = (system.get_file_info(EXEDIR .. PATHSEP .. 'user') and (EXEDIR .. PATHSEP .. 'user')) or os.getenv("LITE_USERDIR") or ((os.getenv("XDG_CONFIG_HOME") and os.getenv("XDG_CONFIG_HOME") .. PATHSEP .. "lite-xl")) diff --git a/data/core/tokenizer.lua b/data/core/tokenizer.lua index 8f3e05d0..46b54639 100644 --- a/data/core/tokenizer.lua +++ b/data/core/tokenizer.lua @@ -123,8 +123,10 @@ local function report_bad_pattern(log_fn, syntax, pattern_idx, msg, ...) end if bad_patterns[syntax][pattern_idx] then return end bad_patterns[syntax][pattern_idx] = true - log_fn("Malformed pattern #%d in %s language plugin. " .. msg, - pattern_idx, syntax.name or "unnamed", ...) + log_fn("Malformed pattern #%d <%s> in %s language plugin.\n" .. msg, + pattern_idx, + syntax.patterns[pattern_idx].pattern or syntax.patterns[pattern_idx].regex, + syntax.name or "unnamed", ...) end ---@param incoming_syntax table @@ -265,7 +267,6 @@ function tokenizer.tokenize(incoming_syntax, text, state, resume) local text_len = text:ulen() local start_time = system.get_time() local starting_i = i - while text_len ~= nil and i <= text_len do -- Every 200 chars, check if we're out of time if i - starting_i > 200 then @@ -334,6 +335,14 @@ function tokenizer.tokenize(incoming_syntax, text, state, resume) for n, p in ipairs(current_syntax.patterns) do local find_results = { find_text(text, p, i, true, false) } if find_results[1] then + -- Check for patterns successfully matching nothing + if find_results[1] > find_results[2] then + report_bad_pattern(core.warn, current_syntax, n, + "Pattern successfully matched, but nothing was captured.") + goto continue + end + + -- Check for patterns with mismatching number of `types` local type_is_table = type(p.type) == "table" local n_types = type_is_table and #p.type or 1 if #find_results == 2 and type_is_table then @@ -347,6 +356,7 @@ function tokenizer.tokenize(incoming_syntax, text, state, resume) report_bad_pattern(core.warn, current_syntax, n, "Too many token types: got %d needed %d.", n_types, #find_results - 1) end + -- matched pattern; make and add tokens push_tokens(res, current_syntax, p, text, find_results) -- update state if this was a start|end pattern pair @@ -362,6 +372,7 @@ function tokenizer.tokenize(incoming_syntax, text, state, resume) i = find_results[2] + 1 matched = true break + ::continue:: end end diff --git a/data/plugins/autocomplete.lua b/data/plugins/autocomplete.lua index cf228b6e..f2e02e28 100644 --- a/data/plugins/autocomplete.lua +++ b/data/plugins/autocomplete.lua @@ -212,12 +212,14 @@ end) local partial = "" +local suggestions_offset = 1 local suggestions_idx = 1 local suggestions = {} local last_line, last_col local function reset_suggestions() + suggestions_offset = 1 suggestions_idx = 1 suggestions = {} @@ -261,6 +263,7 @@ local function update_suggestions() end end suggestions_idx = 1 + suggestions_offset = 1 end local function get_partial_symbol() @@ -276,8 +279,10 @@ local function get_active_view() end end +local last_max_width = 0 local function get_suggestions_rect(av) if #suggestions == 0 then + last_max_width = 0 return 0, 0, 0, 0 end @@ -287,38 +292,47 @@ local function get_suggestions_rect(av) local font = av:get_font() local th = font:get_height() + local ah = config.plugins.autocomplete.max_height + + local max_items = math.min(ah, #suggestions) + + local show_count = math.min(#suggestions, ah) + local start_index = math.max(suggestions_idx-(ah-1), 1) + local max_width = 0 - for _, s in ipairs(suggestions) do + for i = start_index, start_index + show_count - 1 do + local s = suggestions[i] local w = font:get_width(s.text) if s.info then w = w + style.font:get_width(s.info) + style.padding.x end max_width = math.max(max_width, w) end + max_width = math.max(last_max_width, max_width) + last_max_width = max_width - local ah = config.plugins.autocomplete.max_height - - local max_items = #suggestions - if max_items > ah then - max_items = ah - end + max_width = max_width + style.padding.x * 2 + x = x - style.padding.x -- additional line to display total items max_items = max_items + 1 - if max_width < 150 then - max_width = 150 + if max_width > core.root_view.size.x then + max_width = core.root_view.size.x + end + if max_width < 150 * SCALE then + max_width = 150 * SCALE end -- if portion not visiable to right, reposition to DocView right margin - if (x - av.position.x) + max_width > av.size.x then - x = (av.size.x + av.position.x) - max_width - (style.padding.x * 2) + if x + max_width > core.root_view.size.x then + x = (av.size.x + av.position.x) - max_width end return - x - style.padding.x, + x, y - style.padding.y, - max_width + style.padding.x * 2, + max_width, max_items * (th + style.padding.y) + style.padding.y end @@ -446,16 +460,29 @@ local function draw_suggestions_box(av) local font = av:get_font() local lh = font:get_height() + style.padding.y local y = ry + style.padding.y / 2 - local show_count = #suggestions <= ah and #suggestions or ah - local start_index = suggestions_idx > ah and (suggestions_idx-(ah-1)) or 1 + local show_count = math.min(#suggestions, ah) + local start_index = suggestions_offset for i=start_index, start_index+show_count-1, 1 do if not suggestions[i] then break end local s = suggestions[i] + + local info_size = s.info and (style.font:get_width(s.info) + style.padding.x) or style.padding.x + local color = (i == suggestions_idx) and style.accent or style.text - common.draw_text(font, color, s.text, "left", rx + style.padding.x, y, rw, lh) + -- Push clip to avoid that the suggestion text gets drawn over suggestion type/icon + core.push_clip_rect(rx + style.padding.x, y, rw - info_size - style.padding.x, lh) + local x_adv = common.draw_text(font, color, s.text, "left", rx + style.padding.x, y, rw, lh) + core.pop_clip_rect() + -- If the text wasn't fully visible, draw an ellipsis + if x_adv > rx + rw - info_size then + local ellipsis_size = font:get_width("…") + local ell_x = rx + rw - info_size - ellipsis_size + renderer.draw_rect(ell_x, y, ellipsis_size, lh, style.background3) + common.draw_text(font, color, "…", "left", ell_x, y, ellipsis_size, lh) + end if s.info then color = (i == suggestions_idx) and style.text or style.dim common.draw_text(style.font, color, s.info, "right", rx, y, rw - style.padding.x, lh) @@ -641,7 +668,7 @@ command.add(predicate, { local current_partial = get_partial_symbol() local sz = #current_partial - for idx, line1, col1, line2, col2 in doc:get_selections(true) do + for _, line1, col1, line2, _ in doc:get_selections(true) do local n = col1 - 1 local line = doc.lines[line1] for i = 1, sz + 1 do @@ -662,10 +689,24 @@ command.add(predicate, { ["autocomplete:previous"] = function() suggestions_idx = (suggestions_idx - 2) % #suggestions + 1 + + local ah = math.min(config.plugins.autocomplete.max_height, #suggestions) + if suggestions_offset > suggestions_idx then + suggestions_offset = suggestions_idx + elseif suggestions_offset + ah < suggestions_idx + 1 then + suggestions_offset = suggestions_idx - ah + 1 + end end, ["autocomplete:next"] = function() suggestions_idx = (suggestions_idx % #suggestions) + 1 + + local ah = math.min(config.plugins.autocomplete.max_height, #suggestions) + if suggestions_offset + ah < suggestions_idx + 1 then + suggestions_offset = suggestions_idx - ah + 1 + elseif suggestions_offset > suggestions_idx then + suggestions_offset = suggestions_idx + end end, ["autocomplete:cycle"] = function() diff --git a/data/plugins/language_cpp.lua b/data/plugins/language_cpp.lua index 70489713..88f0770f 100644 --- a/data/plugins/language_cpp.lua +++ b/data/plugins/language_cpp.lua @@ -5,7 +5,8 @@ syntax.add { name = "C++", files = { "%.h$", "%.inl$", "%.cpp$", "%.cc$", "%.C$", "%.cxx$", - "%.c++$", "%.hh$", "%.H$", "%.hxx$", "%.hpp$", "%.h++$" + "%.c++$", "%.hh$", "%.H$", "%.hxx$", "%.hpp$", "%.h++$", + "%.ino$" }, comment = "//", block_comment = { "/*", "*/" }, diff --git a/data/plugins/language_js.lua b/data/plugins/language_js.lua index 2eb38741..1921f8d2 100644 --- a/data/plugins/language_js.lua +++ b/data/plugins/language_js.lua @@ -20,10 +20,10 @@ local syntax = require "core.syntax" -- followed by pattern options, and anything that can -- be after a pattern. -- --- Demo with some unit tests (click on the Unit Tests entry): https://regex101.com/r/R0w8Qw/1 +-- Demo with some unit tests (click on the Unit Tests entry): https://regex101.com/r/Vx5L5V/1 -- Note that it has a couple of changes to make it work on that platform. local regex_pattern = { - [=[/(?=(?!/)(?:(?>[^\\[\/]++|\\.|\[(?:[^\\\]]++|\\.)*+\])*+)++/[gmiyuvsd]*\s*[\n,;\)\]\}\.])()]=], + [=[\/(?=(?!\/)(?:(?>[^\\[\/]++|\\.|\[(?:[^\\\]]++|\\.)*+\])*+)++\/[gmiyuvsd]*\s*(?:[\n,;\)\]\}\.]|\/[\/*]))()]=], "/()[gmiyuvsd]*", "\\" } @@ -57,18 +57,19 @@ syntax.add { comment = "//", block_comment = { "/*", "*/" }, patterns = { - { pattern = "//.*", type = "comment" }, - { pattern = { "/%*", "%*/" }, type = "comment" }, - { regex = regex_pattern, syntax = inner_regex_syntax, type = {"string", "string"} }, - { pattern = { '"', '"', '\\' }, type = "string" }, - { pattern = { "'", "'", '\\' }, type = "string" }, - { pattern = { "`", "`", '\\' }, type = "string" }, - { pattern = "-?0[xXbBoO][%da-fA-F_]+n?()%s*()/?", type = {"number", "normal", "operator"} }, - { pattern = "-?%d+[%d%.eE_n]*()%s*()/?", type = {"number", "normal", "operator"} }, - { pattern = "-?%.?%d+()%s*()/?", type = {"number", "normal", "operator"} }, - { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, - { pattern = "[%a_][%w_]*%f[(]", type = "function" }, - { pattern = "[%a_][%w_]*()%s*()/?", type = {"symbol", "normal", "operator"} }, + { pattern = "//.*", type = "comment" }, + { pattern = { "/%*", "%*/" }, type = "comment" }, + { regex = regex_pattern, syntax = inner_regex_syntax, type = {"string", "string"} }, + { pattern = { '"', '"', '\\' }, type = "string" }, + { pattern = { "'", "'", '\\' }, type = "string" }, + { pattern = { "`", "`", '\\' }, type = "string" }, + -- Use (?:\/(?!\/|\*))? to avoid that a regex can start after a number, while also allowing // and /* comments + { regex = [[-?0[xXbBoO][\da-fA-F_]+n?()\s*()(?:\/(?!\/|\*))?]], type = {"number", "normal", "operator"} }, + { regex = [[-?\d+[0-9.eE_n]*()\s*()(?:\/(?!\/|\*))?]], type = {"number", "normal", "operator"} }, + { regex = [[-?\.?\d+()\s*()(?:\/(?!\/|\*))?]], type = {"number", "normal", "operator"} }, + { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, + { pattern = "[%a_][%w_]*%f[(]", type = "function" }, + { pattern = "[%a_][%w_]*", type = "symbol" }, }, symbols = { ["async"] = "keyword", @@ -92,6 +93,7 @@ syntax.add { ["get"] = "keyword", ["if"] = "keyword", ["import"] = "keyword", + ["from"] = "keyword", ["in"] = "keyword", ["of"] = "keyword", ["instanceof"] = "keyword", diff --git a/data/plugins/language_python.lua b/data/plugins/language_python.lua index 220ddd54..f7c09ac3 100644 --- a/data/plugins/language_python.lua +++ b/data/plugins/language_python.lua @@ -3,7 +3,7 @@ local syntax = require "core.syntax" syntax.add { name = "Python", - files = { "%.py$", "%.pyw$", "%.rpy$" }, + files = { "%.py$", "%.pyw$", "%.rpy$", "%.pyi$" }, headers = "^#!.*[ /]python", comment = "#", block_comment = { '"""', '"""' }, diff --git a/meson.build b/meson.build index 3f88be37..9e8e398b 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('lite-xl', ['c'], - version : '2.1.3', + version : '2.1.4', license : 'MIT', meson_version : '>= 0.56', default_options : [ diff --git a/resources/include/lite_xl_plugin_api.h b/resources/include/lite_xl_plugin_api.h index fa31e350..0c5e93e9 100644 --- a/resources/include/lite_xl_plugin_api.h +++ b/resources/include/lite_xl_plugin_api.h @@ -2,13 +2,13 @@ * lite_xl_plugin_api.h * API for writing C extension modules loaded by Lite XL. * This file is licensed under MIT. - * + * * The Lite XL plugin API is quite simple. * You would write a lua C extension and replace any references to lua.h, lauxlib.h * and lualib.h with lite_xl_plugin_api.h. * In your main file (where your entrypoint resides), define LITE_XL_PLUGIN_ENTRYPOINT. * If you have multiple entrypoints, define LITE_XL_PLUGIN_ENTRYPOINT in one of them. - * + * * After that, you need to create a Lite XL entrypoint, which is formatted as * luaopen_lite_xl_xxxxx instead of luaopen_xxxxx. * This entrypoint accepts a lua_State and an extra parameter of type void *. @@ -16,9 +16,9 @@ * If you have multiple entrypoints, you must call lite_xl_plugin_init() in * each of them. * This function is not thread safe, so don't try to do anything stupid. - * + * * An example: - * + * * #define LITE_XL_PLUGIN_ENTRYPOINT * #include "lite_xl_plugin_api.h" * int luaopen_lite_xl_xxxxx(lua_State* L, void* XL) { @@ -26,11 +26,11 @@ * ... * return 1; * } - * + * * You can compile the library just like any Lua library without linking to Lua. * An example command would be: gcc -shared -o xxxxx.so xxxxx.c * You must not link to ANY lua library to avoid symbol collision. - * + * * This file contains stock configuration for a typical installation of Lua 5.4. * DO NOT MODIFY ANYTHING. MODIFYING STUFFS IN HERE WILL BREAK * COMPATIBILITY WITH LITE XL AND CAUSE UNDEBUGGABLE BUGS. @@ -60,8 +60,8 @@ #define FE_7(what, x, ...) what x,FE_6(what, __VA_ARGS__) #define FE_8(what, x, ...) what x,FE_7(what, __VA_ARGS__) #define FOR_EACH_NARG(...) FOR_EACH_NARG_(__VA_ARGS__, FOR_EACH_RSEQ_N()) -#define FOR_EACH_NARG_(...) FOR_EACH_ARG_N(__VA_ARGS__) -#define FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N +#define FOR_EACH_NARG_(...) FOR_EACH_ARG_N(__VA_ARGS__) +#define FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N #define FOR_EACH_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0 #define FOR_EACH_(N, what, ...) CONCAT(FE_, N)(what, __VA_ARGS__) #define FOR_EACH(what, ...) FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__) @@ -2560,4 +2560,4 @@ void lite_xl_plugin_init(void *XL); * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -******************************************************************************/ +******************************************************************************/ diff --git a/resources/linux/com.lite_xl.LiteXL.appdata.xml b/resources/linux/org.lite_xl.lite_xl.appdata.xml similarity index 83% rename from resources/linux/com.lite_xl.LiteXL.appdata.xml rename to resources/linux/org.lite_xl.lite_xl.appdata.xml index 5285cd66..d7b7a9f1 100644 --- a/resources/linux/com.lite_xl.LiteXL.appdata.xml +++ b/resources/linux/org.lite_xl.lite_xl.appdata.xml @@ -1,12 +1,12 @@ - com.lite_xl.LiteXL + org.lite_xl.lite_xl MIT MIT Lite XL A lightweight text editor written in Lua - com.lite_xl.LiteXL.desktop + org.lite_xl.lite_xl.desktop

@@ -29,6 +29,6 @@ - + diff --git a/resources/linux/com.lite_xl.LiteXL.desktop b/resources/linux/org.lite_xl.lite_xl.desktop similarity index 100% rename from resources/linux/com.lite_xl.LiteXL.desktop rename to resources/linux/org.lite_xl.lite_xl.desktop diff --git a/resources/windows/001-lua-unicode.diff b/resources/windows/001-lua-unicode.diff index 6617ad26..31fec364 100644 --- a/resources/windows/001-lua-unicode.diff +++ b/resources/windows/001-lua-unicode.diff @@ -13,9 +13,9 @@ diff -ruN lua-5.4.4\src\luaconf.h lua-5.4.4-patched\src\luaconf.h --- lua-5.4.4\src\luaconf.h Thu Jan 13 19:24:43 2022 +++ lua-5.4.4-patched\src\luaconf.h Wed Feb 22 04:10:02 2023 @@ -782,5 +782,15 @@ - - - + + + +#if defined(lua_c) || defined(luac_c) || (defined(LUA_LIB) && \ + (defined(lauxlib_c) || defined(liolib_c) || \ + defined(loadlib_c) || defined(loslib_c))) @@ -27,19 +27,19 @@ diff -ruN lua-5.4.4\src\luaconf.h lua-5.4.4-patched\src\luaconf.h + + #endif - + diff -ruN lua-5.4.4\src\Makefile lua-5.4.4-patched\src\Makefile --- lua-5.4.4\src\Makefile Thu Jul 15 22:01:52 2021 +++ lua-5.4.4-patched\src\Makefile Wed Feb 22 04:10:02 2023 @@ -33,7 +33,7 @@ PLATS= guess aix bsd c89 freebsd generic linux linux-readline macosx mingw posix solaris - + LUA_A= liblua.a -CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o +CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o utf8_wrappers.o LIB_O= lauxlib.o lbaselib.o lcorolib.o ldblib.o liolib.o lmathlib.o loadlib.o loslib.o lstrlib.o ltablib.o lutf8lib.o linit.o BASE_O= $(CORE_O) $(LIB_O) $(MYOBJS) - + diff -ruN lua-5.4.4\src\utf8_wrappers.c lua-5.4.4-patched\src\utf8_wrappers.c --- lua-5.4.4\src\utf8_wrappers.c Thu Jan 01 08:00:00 1970 +++ lua-5.4.4-patched\src\utf8_wrappers.c Wed Feb 22 18:13:45 2023 diff --git a/scripts/common.sh b/scripts/common.sh index 14402138..831fee1b 100644 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -77,11 +77,17 @@ get_platform_arch() { platform=$(get_platform_name) arch=${CROSS_ARCH:-$(uname -m)} if [[ $MSYSTEM != "" ]]; then - if [[ $MSYSTEM == "MINGW64" ]]; then + case "$MSYSTEM" in + MINGW64|UCRT64|CLANG64) arch=x86_64 - else + ;; + MINGW32|CLANG32) arch=i686 - fi + ;; + CLANGARM64) + arch=aarch64 + ;; + esac fi echo "$arch" } diff --git a/scripts/innosetup/innosetup.iss.in b/scripts/innosetup/innosetup.iss.in index 5b2d41b2..1d64e4f6 100644 --- a/scripts/innosetup/innosetup.iss.in +++ b/scripts/innosetup/innosetup.iss.in @@ -26,12 +26,16 @@ AppPublisherURL={#MyAppURL} AppSupportURL={#MyAppURL} AppUpdatesURL={#MyAppURL} -#if Arch=="x64" - ArchitecturesAllowed=x64 - ArchitecturesInstallIn64BitMode=x64 - #define ArchInternal "x86_64" -#else +#if Arch=="x86" #define ArchInternal "i686" +#else + ArchitecturesAllowed={#Arch} + ArchitecturesInstallIn64BitMode={#Arch} + #if Arch=="x64" + #define ArchInternal "x86_64" + #elif Arch=="arm64" + #define ArchInternal "aarch64" + #endif #endif AllowNoIcons=yes diff --git a/scripts/innosetup/innosetup.sh b/scripts/innosetup/innosetup.sh index a37a2836..86ab89d1 100644 --- a/scripts/innosetup/innosetup.sh +++ b/scripts/innosetup/innosetup.sh @@ -29,13 +29,24 @@ main() { local version local output - if [[ $MSYSTEM == "MINGW64" ]]; then + case "$MSYSTEM" in + MINGW64|UCRT64|CLANG64) arch=x64 arch_file=x86_64 - else - arch=i686; + ;; + MINGW32|CLANG32) + arch=x86 arch_file=i686 - fi + ;; + CLANGARM64) + arch=arm64 + arch_file=aarch64 + ;; + *) + echo "error: unsupported MSYSTEM type: $MSYSTEM" + exit 1 + ;; + esac initial_arg_count=$# diff --git a/scripts/package.sh b/scripts/package.sh index d9a9c14c..46d6c231 100644 --- a/scripts/package.sh +++ b/scripts/package.sh @@ -213,14 +213,18 @@ main() { if [[ $platform == "windows" ]]; then exe_file="${exe_file}.exe" stripcmd="strip --strip-all" - # Copy MinGW libraries dependencies. - # MSYS2 ldd command seems to be only 64bit, so use ntldd - # see https://github.com/msys2/MINGW-packages/issues/4164 - ntldd -R "${exe_file}" \ - | grep mingw \ - | awk '{print $3}' \ - | sed 's#\\#/#g' \ - | xargs -I '{}' cp -v '{}' "$(pwd)/${dest_dir}/" + if command -v ntldd >/dev/null 2>&1; then + # Copy MinGW libraries dependencies. + # MSYS2 ldd command seems to be only 64bit, so use ntldd + # see https://github.com/msys2/MINGW-packages/issues/4164 + ntldd -R "${exe_file}" \ + | grep mingw \ + | awk '{print $3}' \ + | sed 's#\\#/#g' \ + | xargs -I '{}' cp -v '{}' "$(pwd)/${dest_dir}/" + else + echo "WARNING: ntldd not found; assuming program is static" + fi else # Windows archive is always portable package_name+="-portable" diff --git a/src/api/api.c b/src/api/api.c index bd22b9fa..7cded575 100644 --- a/src/api/api.c +++ b/src/api/api.c @@ -29,3 +29,4 @@ void api_load_libs(lua_State *L) { for (int i = 0; libs[i].name; i++) luaL_requiref(L, libs[i].name, libs[i].func, 1); } + diff --git a/src/api/process.c b/src/api/process.c index 7a1aa73b..00152578 100644 --- a/src/api/process.c +++ b/src/api/process.c @@ -39,6 +39,7 @@ typedef wchar_t *process_env_t; #define HANDLE_INVALID (INVALID_HANDLE_VALUE) #define PROCESS_GET_HANDLE(P) ((P)->process_information.hProcess) +#define PROCESS_ARGLIST_INITIALIZER { 0 } static volatile long PipeSerialNumber; @@ -52,6 +53,7 @@ typedef char **process_env_t; #define HANDLE_INVALID (0) #define PROCESS_GET_HANDLE(P) ((P)->pid) +#define PROCESS_ARGLIST_INITIALIZER NULL #endif @@ -440,6 +442,7 @@ static int process_arglist_add(process_arglist_t *list, size_t *list_len, const static void process_arglist_free(process_arglist_t *list) { + if (!*list) return; #ifndef _WIN32 char **cmd = *list; for (int i = 0; cmd[i]; i++) @@ -577,7 +580,8 @@ static void process_env_free(process_env_t *list, size_t list_len) { static int process_start(lua_State* L) { int r, retval = 1; size_t env_len = 0, cmd_len = 0, arglist_len = 0, env_vars_len = 0; - process_arglist_t arglist; + process_t *self = NULL; + process_arglist_t arglist = PROCESS_ARGLIST_INITIALIZER; process_env_t env_vars = NULL; const char *cwd = NULL; bool detach = false, escape = true; @@ -667,7 +671,7 @@ static int process_start(lua_State* L) { lua_pop(L, 1); } - process_t* self = lua_newuserdata(L, sizeof(process_t)); + self = lua_newuserdata(L, sizeof(process_t)); memset(self, 0, sizeof(process_t)); luaL_setmetatable(L, API_TYPE_PROCESS); self->deadline = deadline; @@ -825,10 +829,12 @@ static int process_start(lua_State* L) { if (control_pipe[0]) close(control_pipe[0]); if (control_pipe[1]) close(control_pipe[1]); #endif - for (int stream = 0; stream < 3; ++stream) { - process_stream_t* pipe = &self->child_pipes[stream][stream == STDIN_FD ? 0 : 1]; - if (*pipe) { - close_fd(pipe); + if (self) { + for (int stream = 0; stream < 3; ++stream) { + process_stream_t* pipe = &self->child_pipes[stream][stream == STDIN_FD ? 0 : 1]; + if (*pipe) { + close_fd(pipe); + } } } process_arglist_free(&arglist); @@ -848,7 +854,7 @@ static int g_read(lua_State* L, int stream, unsigned long read_size) { return luaL_error(L, "error: redirect to handles, FILE* and paths are not supported"); #if _WIN32 int writable_stream_idx = stream - 1; - if (self->reading[writable_stream_idx] || !ReadFile(self->child_pipes[stream][0], self->buffer[writable_stream_idx], READ_BUF_SIZE, NULL, &self->overlapped[writable_stream_idx])) { + if (self->reading[writable_stream_idx] || !ReadFile(self->child_pipes[stream][0], self->buffer[writable_stream_idx], read_size > READ_BUF_SIZE ? READ_BUF_SIZE : read_size, NULL, &self->overlapped[writable_stream_idx])) { if (self->reading[writable_stream_idx] || GetLastError() == ERROR_IO_PENDING) { self->reading[writable_stream_idx] = true; DWORD bytesTransferred = 0;