Compare commits

...

30 Commits

Author SHA1 Message Date
George Sokianos 79f0ac4f80 Applied PR390 2022-01-07 11:19:15 +00:00
George Sokianos ce62b9c8da Applied PR255 changes 2022-01-07 11:00:50 +00:00
George Sokianos fb3d36da43 Some fixes on the README_OS4.md file 2022-01-06 20:22:35 +00:00
George Sokianos 94807d505c Added 'SDL_RENDERER_ACCELERATED' and 'SDL_RENDERER_PRESENTVSYNC' on SDL_CreateRenderer() 2022-01-05 22:13:35 +00:00
George Sokianos 44cd036b7a Added "SDL_RENDERER_ACCELERATED 2022-01-05 22:12:18 +00:00
George Sokianos 3c7da82ad2 Added the latest update version file in repo 2022-01-05 20:05:56 +00:00
George Sokianos d30a9622a5 Added config.scroll_past_end 2022-01-05 20:03:20 +00:00
George Sokianos 2fdf19ec49 Prepare 1.16.12.6 release 2022-01-04 12:47:51 +00:00
George Sokianos 9f656f8ab4 Fixed the issue with the current path introduced in 1.16.12.5 release #13 2022-01-03 21:25:25 +00:00
George Sokianos 32a3d4b933 Prepare 1.16.12.5 release 2022-01-03 00:53:13 +00:00
George Sokianos c5309e04d6 Fixed loading the current folder from terminal using the dot character 2022-01-03 00:43:04 +00:00
George Sokianos 1c3f766e6b Fixed the resolution on fullscreen toggle to be like the workbench (#4) 2022-01-02 23:47:50 +00:00
George Sokianos de6c0fd575 Removed the extra title bar when return from fullscreen 2022-01-02 23:47:19 +00:00
George Sokianos 7bd164b17e Added a workaround to fix the window resize assertion crash #2 2022-01-02 21:04:41 +00:00
George Sokianos de3e4815ee Removed clearQuit() and applied commit 456f6ed changes to free the resources 2022-01-02 19:04:18 +00:00
George Sokianos b5d4f3f0f8 Prepare 1.16.12.4 release 2021-12-31 12:15:39 +00:00
George Sokianos a788ac871b Fixed the gfx memory leak 2021-12-31 12:15:15 +00:00
George Sokianos 1f27d6f923 Removed some commented code 2021-12-31 12:14:48 +00:00
George Sokianos 5af782b884 prepare 1.16.12.3 release 2021-12-29 13:15:35 +00:00
George Sokianos 95ece12d74 Added Makefile and releases files 2021-12-27 15:11:10 +00:00
George Sokianos 03f2818657 Added more information at README_OS4 file 2021-12-26 17:26:15 +00:00
George Sokianos 689901daca Added Amiga version and cookie stack 2021-12-26 17:15:22 +00:00
George Sokianos 4499f1f111 Some code cleanup and added .config folder to gitignore 2021-12-26 17:08:09 +00:00
George Sokianos 14d813cea1 Made HOME optional and added some caching at the _fullpath() 2021-12-26 17:04:00 +00:00
George Sokianos 2c711138d7 Removed the AMIGAOS4 global variable and now I am using the PLATFORM one to determine the running platform 2021-12-22 19:10:33 +00:00
George Sokianos ff535843e8 Fixed keyboard shortcuts 2021-12-21 20:26:28 +00:00
George Sokianos fdd2f3af33 Fixed a forgotten hardcoded path 2021-12-21 18:27:25 +00:00
George Sokianos 7c85530e92 Added icon and OS4 readme file 2021-12-21 17:56:49 +00:00
George Sokianos e13efe91b4 Added the build script for font renderer 2021-12-21 17:55:37 +00:00
George Sokianos c155f797cf First commit of compilable code for OS4 2021-12-21 17:52:44 +00:00
89 changed files with 756 additions and 286 deletions

2
.gitignore vendored
View File

@ -7,3 +7,5 @@ build*
subprojects/lua subprojects/lua
subprojects/libagg subprojects/libagg
sybprojects/lua sybprojects/lua
lite
.config/

25
Makefile.os4 Normal file
View File

@ -0,0 +1,25 @@
#
# Project: Lite XL
#
# Created on: 26-12-2021
#
.PHONY: build release
default: build
build:
@sh os4build.sh
release:
mkdir -p release/LiteXL
cp release_files/* release/LiteXL/ -r
mv release/LiteXL/LiteXL.info release/
cp data release/LiteXL/ -r
cp doc release/LiteXL/ -r
cp lite release/LiteXL/
strip release/LiteXL/lite
cp README.md release/LiteXL/
cp README_OS4.md release/LiteXL/
cp LICENSE release/LiteXL/
lha -aeqr3 a LiteXL.lha release/

93
README_OS4.md Normal file
View File

@ -0,0 +1,93 @@
# Lite XL for AmigaOS 4.1 FE
Lite XL is coming to AmigaOS 4.1.
A few things are not quite working. Please have a look at the "Known issues"
section below.
## Installation
You can extract the Lite XL archive wherever you want and run the *lite*
editor.
## Configuration folder
This editor creates a `.config` folder where the configuration is saved, as
well as plugins, themes etc.. By default this AmigaOS 4.1 FE version uses the
executable folder, but if you want to ovveride it, create an ENV variable
named `HOME` and set there your path.
You can check if there is one already set by executing the following command
in a shell
```
GetEnv HOME
```
If there is one set, then you will see the path at the output.
Otherwise, you can set your home path be executing the following command.
Change the path to the one of your preference.
```
SetEnv SAVE HOME "Sys:home/"
```
## Know issues
You can find the known issues at
https://git.walkero.gr/walkero/lite-xl/issues
# Changelog
## [1.16.12.7] - future
## Added
- Added config.scroll_past_end that when its true lets the user scroll
further than the end of the file. By default is set to true.
- Added "SDL_RENDERER_ACCELERATED" and "SDL_RENDERER_PRESENTVSYNC" on
SDL_CreateRenderer() since this reduces the CPU usage when the user
scrolls and seems to work pretty good on my systems (X5000, A1222 and
microAmigaOne). This is exeprimental. If this brings problems on your
system, you can disable them using SDL ENV variable, like below:
setenv SDL_RENDER_VSYNC 0
setenv SDL_RENDER_DRIVER "software"
## [1.16.12.6] - 2022-01-04
### Fixed
- Fixed a problem introduced in previous version when LiteXL was executed
from the root path of a partition or from ram disk (#13)
## [1.16.12.5] - 2022-01-03
### Changed
- Changed the Gfx memory leak solution to a fix that was applied by the
editor development team on Lua scripts at a later version. Less custom
code for AmigaOS 4 port.
- Now, when return from fullscreen, there is no extra header visible
at the top of the window content
### Fixed
- Fixed the assertion error and crash when the window is resized (#2)
- Fixed the resolution on fullscreen toggle to be like the workbench (#4)
- Fixed loading the current folder from terminal using the dot, like
`lite .` or without it (#3)
## [1.16.12.4] - 2021-12-31
### Fixed
- Fixed the Gfx memory leak. Now LiteXL frees the reserved memory from the
gfx card.
## [1.16.12.3] - 2021-12-29
### Changed
- Compiled with an experimental version of the latest Anti-Grain Geometry
library. This is might have issues and crash LiteXL
## [1.16.12.2] - 2021-12-26
### Added
- Added Amiga version. This version of LiteXL is based on v1.16.12 source code
which will not change. I will use the fourth digit to distinguish different
AmigaOS 4 releases, until a new port of the latest available source (v2.x)
is made.
### Fixed
- The keyboard shortcuts are now working
### Changed
- Now the `HOME` ENV variable is optional. If this is not set, the LiteXL
folder will be used to create user's `.config` folder

BIN
README_OS4.md.info Normal file

Binary file not shown.

0
data/colors/fall.lua Normal file → Executable file
View File

0
data/colors/summer.lua Normal file → Executable file
View File

0
data/core/command.lua Normal file → Executable file
View File

0
data/core/commands/command.lua Normal file → Executable file
View File

View File

@ -6,6 +6,7 @@ local LogView = require "core.logview"
local fullscreen = false local fullscreen = false
local restore_title_view = false
local function suggest_directory(text) local function suggest_directory(text)
text = common.home_expand(text) text = common.home_expand(text)
@ -27,9 +28,12 @@ command.add(nil, {
["core:toggle-fullscreen"] = function() ["core:toggle-fullscreen"] = function()
fullscreen = not fullscreen fullscreen = not fullscreen
if fullscreen then
restore_title_view = core.title_view.visible
end
system.set_window_mode(fullscreen and "fullscreen" or "normal") system.set_window_mode(fullscreen and "fullscreen" or "normal")
core.show_title_bar(not fullscreen) core.show_title_bar(not fullscreen and restore_title_view)
core.title_view:configure_hit_test(not fullscreen) core.title_view:configure_hit_test(not fullscreen and restore_title_view)
end, end,
["core:reload-module"] = function() ["core:reload-module"] = function()

349
data/core/commands/doc.lua Normal file → Executable file
View File

@ -24,13 +24,16 @@ local function get_indent_string()
end end
local function doc_multiline_selection(sort) local function doc_multiline_selections(sort)
local line1, col1, line2, col2, swap = doc():get_selection(sort) local iter, state, idx, line1, col1, line2, col2 = doc():get_selections(sort)
if line2 > line1 and col2 == 1 then return function()
line2 = line2 - 1 idx, line1, col1, line2, col2 = iter(state, idx)
col2 = #doc().lines[line2] if idx and line2 > line1 and col2 == 1 then
line2 = line2 - 1
col2 = #doc().lines[line2]
end
return idx, line1, col1, line2, col2
end end
return line1, col1, line2, col2, swap
end end
local function append_line_if_last_line(line) local function append_line_if_last_line(line)
@ -39,7 +42,6 @@ local function append_line_if_last_line(line)
end end
end end
local function save(filename) local function save(filename)
doc():save(filename and core.normalize_to_project_dir(filename)) doc():save(filename and core.normalize_to_project_dir(filename))
local saved_filename = doc().filename local saved_filename = doc().filename
@ -47,55 +49,31 @@ local function save(filename)
core.log("Saved \"%s\"", saved_filename) core.log("Saved \"%s\"", saved_filename)
end end
-- returns the size of the original indent, and the indent local function cut_or_copy(delete)
-- in your config format, rounded either up or down local full_text = ""
local function get_line_indent(line, rnd_up) for idx, line1, col1, line2, col2 in doc():get_selections() do
local _, e = line:find("^[ \t]+") if line1 ~= line2 or col1 ~= col2 then
local soft_tab = string.rep(" ", config.indent_size) local text = doc():get_text(line1, col1, line2, col2)
if config.tab_type == "hard" then if delete then
local indent = e and line:sub(1, e):gsub(soft_tab, "\t") or "" doc():delete_to_cursor(idx, 0)
return e, indent:gsub(" +", rnd_up and "\t" or "") end
else full_text = full_text == "" and text or (full_text .. "\n" .. text)
local indent = e and line:sub(1, e):gsub("\t", soft_tab) or "" doc().cursor_clipboard[idx] = text
local number = #indent / #soft_tab else
return e, indent:sub(1, doc().cursor_clipboard[idx] = ""
(rnd_up and math.ceil(number) or math.floor(number))*#soft_tab) end
end end
system.set_clipboard(full_text)
end end
-- un/indents text; behaviour varies based on selection and un/indent. local function split_cursor(direction)
-- * if there's a selection, it will stay static around the local new_cursors = {}
-- text for both indenting and unindenting. for _, line1, col1 in doc():get_selections() do
-- * if you are in the beginning whitespace of a line, and are indenting, the if line1 + direction >= 1 and line1 + direction <= #doc().lines then
-- cursor will insert the exactly appropriate amount of spaces, and jump the table.insert(new_cursors, { line1 + direction, col1 })
-- cursor to the beginning of first non whitespace characters
-- * if you are not in the beginning whitespace of a line, and you indent, it
-- inserts the appropriate whitespace, as if you typed them normally.
-- * if you are unindenting, the cursor will jump to the start of the line,
-- and remove the appropriate amount of spaces (or a tab).
local function indent_text(unindent)
local text = get_indent_string()
local line1, col1, line2, col2, swap = doc_multiline_selection(true)
local _, se = doc().lines[line1]:find("^[ \t]+")
local in_beginning_whitespace = col1 == 1 or (se and col1 <= se + 1)
if unindent or doc():has_selection() or in_beginning_whitespace then
local l1d, l2d = #doc().lines[line1], #doc().lines[line2]
for line = line1, line2 do
local e, rnded = get_line_indent(doc().lines[line], unindent)
doc():remove(line, 1, line, (e or 0) + 1)
doc():insert(line, 1,
unindent and rnded:sub(1, #rnded - #text) or rnded .. text)
end end
l1d, l2d = #doc().lines[line1] - l1d, #doc().lines[line2] - l2d
if (unindent or in_beginning_whitespace) and not doc():has_selection() then
local start_cursor = (se and se + 1 or 1) + l1d or #(doc().lines[line1])
doc():set_selection(line1, start_cursor, line2, start_cursor, swap)
else
doc():set_selection(line1, col1 + l1d, line2, col2 + l2d, swap)
end
else
doc():text_input(text)
end end
for i,v in ipairs(new_cursors) do doc():add_selection(v[1], v[2]) end
end end
local commands = { local commands = {
@ -108,65 +86,66 @@ local commands = {
end, end,
["doc:cut"] = function() ["doc:cut"] = function()
if doc():has_selection() then cut_or_copy(true)
local text = doc():get_text(doc():get_selection())
system.set_clipboard(text)
doc():delete_to(0)
end
end, end,
["doc:copy"] = function() ["doc:copy"] = function()
if doc():has_selection() then cut_or_copy(false)
local text = doc():get_text(doc():get_selection())
system.set_clipboard(text)
end
end, end,
["doc:paste"] = function() ["doc:paste"] = function()
doc():text_input(system.get_clipboard():gsub("\r", "")) for idx, line1, col1, line2, col2 in doc():get_selections() do
local value = doc().cursor_clipboard[idx] or system.get_clipboard()
doc():text_input(value:gsub("\r", ""), idx)
end
end, end,
["doc:newline"] = function() ["doc:newline"] = function()
local line, col = doc():get_selection() for idx, line, col in doc():get_selections(false, true) do
local indent = doc().lines[line]:match("^[\t ]*") local indent = doc().lines[line]:match("^[\t ]*")
if col <= #indent then if col <= #indent then
indent = indent:sub(#indent + 2 - col) indent = indent:sub(#indent + 2 - col)
end
doc():text_input("\n" .. indent, idx)
end end
doc():text_input("\n" .. indent)
end, end,
["doc:newline-below"] = function() ["doc:newline-below"] = function()
local line = doc():get_selection() for idx, line in doc():get_selections(false, true) do
local indent = doc().lines[line]:match("^[\t ]*") local indent = doc().lines[line]:match("^[\t ]*")
doc():insert(line, math.huge, "\n" .. indent) doc():insert(line, math.huge, "\n" .. indent)
doc():set_selection(line + 1, math.huge) doc():set_selections(idx, line + 1, math.huge)
end
end, end,
["doc:newline-above"] = function() ["doc:newline-above"] = function()
local line = doc():get_selection() for idx, line in doc():get_selections(false, true) do
local indent = doc().lines[line]:match("^[\t ]*") local indent = doc().lines[line]:match("^[\t ]*")
doc():insert(line, 1, indent .. "\n") doc():insert(line, 1, indent .. "\n")
doc():set_selection(line, math.huge) doc():set_selections(idx, line, math.huge)
end
end, end,
["doc:delete"] = function() ["doc:delete"] = function()
local line, col = doc():get_selection() for idx, line1, col1, line2, col2 in doc():get_selections() do
if not doc():has_selection() and doc().lines[line]:find("^%s*$", col) then if line1 == line2 and col1 == col2 and doc().lines[line1]:find("^%s*$", col1) then
doc():remove(line, col, line, math.huge) doc():remove(line1, col1, line1, math.huge)
end
doc():delete_to_cursor(idx, translate.next_char)
end end
doc():delete_to(translate.next_char)
end, end,
["doc:backspace"] = function() ["doc:backspace"] = function()
local line, col = doc():get_selection() for idx, line1, col1, line2, col2 in doc():get_selections() do
if not doc():has_selection() then if line1 == line2 and col1 == col2 then
local text = doc():get_text(line, 1, line, col) local text = doc():get_text(line1, 1, line1, col1)
if #text >= config.indent_size and text:find("^ *$") then if #text >= config.indent_size and text:find("^ *$") then
doc():delete_to(0, -config.indent_size) doc():delete_to_cursor(idx, 0, -config.indent_size)
return return
end
end end
doc():delete_to_cursor(idx, translate.previous_char)
end end
doc():delete_to(translate.previous_char)
end, end,
["doc:select-all"] = function() ["doc:select-all"] = function()
@ -177,77 +156,104 @@ local commands = {
local line, col = doc():get_selection() local line, col = doc():get_selection()
doc():set_selection(line, col) doc():set_selection(line, col)
end, end,
["doc:indent"] = function()
for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do
local l1, c1, l2, c2 = doc():indent_text(false, line1, col1, line2, col2)
if l1 then
doc():set_selections(idx, l1, c1, l2, c2)
end
end
end,
["doc:select-lines"] = function() ["doc:select-lines"] = function()
local line1, _, line2, _, swap = doc():get_selection(true) for idx, line1, _, line2 in doc():get_selections(true) do
append_line_if_last_line(line2) append_line_if_last_line(line2)
doc():set_selection(line1, 1, line2 + 1, 1, swap) doc():set_selections(idx, line1, 1, line2 + 1, 1, swap)
end
end, end,
["doc:select-word"] = function() ["doc:select-word"] = function()
local line1, col1 = doc():get_selection(true) for idx, line1, col1 in doc():get_selections(true) do
local line1, col1 = translate.start_of_word(doc(), line1, col1) local line1, col1 = translate.start_of_word(doc(), line1, col1)
local line2, col2 = translate.end_of_word(doc(), line1, col1) local line2, col2 = translate.end_of_word(doc(), line1, col1)
doc():set_selection(line2, col2, line1, col1) doc():set_selections(idx, line2, col2, line1, col1)
end
end, end,
["doc:join-lines"] = function() ["doc:join-lines"] = function()
local line1, _, line2 = doc():get_selection(true) for idx, line1, col1, line2, col2 in doc():get_selections(true) do
if line1 == line2 then line2 = line2 + 1 end if line1 == line2 then line2 = line2 + 1 end
local text = doc():get_text(line1, 1, line2, math.huge) local text = doc():get_text(line1, 1, line2, math.huge)
text = text:gsub("(.-)\n[\t ]*", function(x) text = text:gsub("(.-)\n[\t ]*", function(x)
return x:find("^%s*$") and x or x .. " " return x:find("^%s*$") and x or x .. " "
end) end)
doc():insert(line1, 1, text) doc():insert(line1, 1, text)
doc():remove(line1, #text + 1, line2, math.huge) doc():remove(line1, #text + 1, line2, math.huge)
if doc():has_selection() then if line1 ~= line2 or col1 ~= col2 then
doc():set_selection(line1, math.huge) doc():set_selections(idx, line1, math.huge)
end
end end
end, end,
["doc:indent"] = function() ["doc:indent"] = function()
indent_text() for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do
local l1, c1, l2, c2 = doc():indent_text(false, line1, col1, line2, col2)
if l1 then
doc():set_selections(idx, l1, c1, l2, c2)
end
end
end, end,
["doc:unindent"] = function() ["doc:unindent"] = function()
indent_text(true) for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do
local l1, c1, l2, c2 = doc():indent_text(true, line1, col1, line2, col2)
if l1 then
doc():set_selections(idx, l1, c1, l2, c2)
end
end
end, end,
["doc:duplicate-lines"] = function() ["doc:duplicate-lines"] = function()
local line1, col1, line2, col2, swap = doc_multiline_selection(true) for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do
append_line_if_last_line(line2) append_line_if_last_line(line2)
local text = doc():get_text(line1, 1, line2 + 1, 1) local text = doc():get_text(line1, 1, line2 + 1, 1)
doc():insert(line2 + 1, 1, text) doc():insert(line2 + 1, 1, text)
local n = line2 - line1 + 1 local n = line2 - line1 + 1
doc():set_selection(line1 + n, col1, line2 + n, col2, swap) doc():set_selections(idx, line1 + n, col1, line2 + n, col2, swap)
end
end, end,
["doc:delete-lines"] = function() ["doc:delete-lines"] = function()
local line1, col1, line2 = doc_multiline_selection(true) for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do
append_line_if_last_line(line2) append_line_if_last_line(line2)
doc():remove(line1, 1, line2 + 1, 1) doc():remove(line1, 1, line2 + 1, 1)
doc():set_selection(line1, col1) doc():set_selections(idx, line1, col1)
end
end, end,
["doc:move-lines-up"] = function() ["doc:move-lines-up"] = function()
local line1, col1, line2, col2, swap = doc_multiline_selection(true) for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do
append_line_if_last_line(line2) append_line_if_last_line(line2)
if line1 > 1 then if line1 > 1 then
local text = doc().lines[line1 - 1] local text = doc().lines[line1 - 1]
doc():insert(line2 + 1, 1, text) doc():insert(line2 + 1, 1, text)
doc():remove(line1 - 1, 1, line1, 1) doc():remove(line1 - 1, 1, line1, 1)
doc():set_selection(line1 - 1, col1, line2 - 1, col2, swap) doc():set_selections(idx, line1 - 1, col1, line2 - 1, col2)
end
end end
end, end,
["doc:move-lines-down"] = function() ["doc:move-lines-down"] = function()
local line1, col1, line2, col2, swap = doc_multiline_selection(true) for idx, line1, col1, line2, col2 in doc_multiline_selections(true) do
append_line_if_last_line(line2 + 1) append_line_if_last_line(line2 + 1)
if line2 < #doc().lines then if line2 < #doc().lines then
local text = doc().lines[line2 + 1] local text = doc().lines[line2 + 1]
doc():remove(line2 + 1, 1, line2 + 2, 1) doc():remove(line2 + 1, 1, line2 + 2, 1)
doc():insert(line1, 1, text) doc():insert(line1, 1, text)
doc():set_selection(line1 + 1, col1, line2 + 1, col2, swap) doc():set_selections(idx, line1 + 1, col1, line2 + 1, col2)
end
end end
end, end,
@ -256,28 +262,29 @@ local commands = {
if not comment then return end if not comment then return end
local indentation = get_indent_string() local indentation = get_indent_string()
local comment_text = comment .. " " local comment_text = comment .. " "
local line1, _, line2 = doc_multiline_selection(true) for idx, line1, _, line2 in doc_multiline_selections(true) do
local uncomment = true local uncomment = true
local start_offset = math.huge local start_offset = math.huge
for line = line1, line2 do for line = line1, line2 do
local text = doc().lines[line] local text = doc().lines[line]
local s = text:find("%S") local s = text:find("%S")
local cs, ce = text:find(comment_text, s, true)
if s and cs ~= s then
uncomment = false
start_offset = math.min(start_offset, s)
end
end
for line = line1, line2 do
local text = doc().lines[line]
local s = text:find("%S")
if uncomment then
local cs, ce = text:find(comment_text, s, true) local cs, ce = text:find(comment_text, s, true)
if ce then if s and cs ~= s then
doc():remove(line, cs, line, ce + 1) uncomment = false
start_offset = math.min(start_offset, s)
end
end
for line = line1, line2 do
local text = doc().lines[line]
local s = text:find("%S")
if uncomment then
local cs, ce = text:find(comment_text, s, true)
if ce then
doc():remove(line, cs, line, ce + 1)
end
elseif s then
doc():insert(line, start_offset, comment_text)
end end
elseif s then
doc():insert(line, start_offset, comment_text)
end end
end end
end, end,
@ -363,6 +370,32 @@ local commands = {
end end
end, common.path_suggest) end, common.path_suggest)
end, end,
["file:delete"] = function()
local filename = doc().abs_filename
if not filename then
core.error("Cannot remove unsaved doc")
return
end
for i,docview in ipairs(core.get_views_referencing_doc(doc())) do
local node = core.root_view.root_node:get_node_for_view(docview)
node:close_view(core.root_view, docview)
end
os.remove(filename)
core.log("Removed \"%s\"", filename)
end,
["doc:create-cursor-previous-line"] = function()
split_cursor(-1)
doc():merge_cursors()
end,
["doc:create-cursor-next-line"] = function()
split_cursor(1)
doc():merge_cursors()
end
} }
@ -392,21 +425,21 @@ for name, fn in pairs(translations) do
end end
commands["doc:move-to-previous-char"] = function() commands["doc:move-to-previous-char"] = function()
if doc():has_selection() then for idx, line1, col1, line2, col2 in doc():get_selections(true) do
local line, col = doc():get_selection(true) if line1 ~= line2 or col1 ~= col2 then
doc():set_selection(line, col) doc():set_selections(idx, line1, col1)
else end
doc():move_to(translate.previous_char)
end end
doc():move_to(translate.previous_char)
end end
commands["doc:move-to-next-char"] = function() commands["doc:move-to-next-char"] = function()
if doc():has_selection() then for idx, line1, col1, line2, col2 in doc():get_selections(true) do
local _, _, line, col = doc():get_selection(true) if line1 ~= line2 or col1 ~= col2 then
doc():set_selection(line, col) doc():set_selections(idx, line2, col2)
else end
doc():move_to(translate.next_char)
end end
doc():move_to(translate.next_char)
end end
command.add("core.docview", commands) command.add("core.docview", commands)

0
data/core/commands/drawwhitespace.lua Normal file → Executable file
View File

0
data/core/commands/files.lua Normal file → Executable file
View File

0
data/core/commands/findreplace.lua Normal file → Executable file
View File

0
data/core/commands/root.lua Normal file → Executable file
View File

0
data/core/commandview.lua Normal file → Executable file
View File

20
data/core/common.lua Normal file → Executable file
View File

@ -54,6 +54,26 @@ function common.color(str)
end end
function common.splice(t, at, remove, insert)
insert = insert or {}
local offset = #insert - remove
local old_len = #t
if offset < 0 then
for i = at - offset, old_len - offset do
t[i + offset] = t[i]
end
elseif offset > 0 then
for i = old_len, at, -1 do
t[i + offset] = t[i]
end
end
for i, item in ipairs(insert) do
t[at + i - 1] = item
end
end
local function compare_score(a, b) local function compare_score(a, b)
return a.score > b.score return a.score > b.score
end end

View File

@ -6,6 +6,7 @@ config.max_log_items = 80
config.message_timeout = 5 config.message_timeout = 5
config.mouse_wheel_scroll = 50 * SCALE config.mouse_wheel_scroll = 50 * SCALE
config.file_size_limit = 10 config.file_size_limit = 10
config.scroll_past_end = true
config.ignore_files = "^%." config.ignore_files = "^%."
config.symbol_pattern = "[%a_][%w_]*" config.symbol_pattern = "[%a_][%w_]*"
config.non_word_chars = " \t\n/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-" config.non_word_chars = " \t\n/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-"

0
data/core/doc/highlighter.lua Normal file → Executable file
View File

250
data/core/doc/init.lua Normal file → Executable file
View File

@ -16,26 +16,6 @@ local function split_lines(text)
return res return res
end end
local function splice(t, at, remove, insert)
insert = insert or {}
local offset = #insert - remove
local old_len = #t
if offset < 0 then
for i = at - offset, old_len - offset do
t[i + offset] = t[i]
end
elseif offset > 0 then
for i = old_len, at, -1 do
t[i + offset] = t[i]
end
end
for i, item in ipairs(insert) do
t[at + i - 1] = item
end
end
function Doc:new(filename) function Doc:new(filename)
self:reset() self:reset()
if filename then if filename then
@ -46,7 +26,8 @@ end
function Doc:reset() function Doc:reset()
self.lines = { "\n" } self.lines = { "\n" }
self.selection = { a = { line=1, col=1 }, b = { line=1, col=1 } } self.selections = { 1, 1, 1, 1 }
self.cursor_clipboard = {}
self.undo_stack = { idx = 1 } self.undo_stack = { idx = 1 }
self.redo_stack = { idx = 1 } self.redo_stack = { idx = 1 }
self.clean_change_id = 1 self.clean_change_id = 1
@ -126,45 +107,87 @@ function Doc:get_change_id()
return self.undo_stack.idx return self.undo_stack.idx
end end
-- Cursor section. Cursor indices are *only* valid during a get_selections() call.
-- Cursors will always be iterated in order from top to bottom. Through normal operation
-- curors can never swap positions; only merge or split, or change their position in cursor
-- order.
function Doc:get_selection(sort)
local idx, line1, col1, line2, col2 = self:get_selections(sort)({ self.selections, sort }, 0)
return line1, col1, line2, col2, sort
end
function Doc:set_selection(line1, col1, line2, col2, swap) function Doc:has_selection()
assert(not line2 == not col2, "expected 2 or 4 arguments") local line1, col1, line2, col2 = self:get_selection(false)
return line1 ~= line2 or col1 ~= col2
end
function Doc:sanitize_selection()
for idx, line1, col1, line2, col2 in self:get_selections() do
self:set_selections(idx, line1, col1, line2, col2)
end
end
local function sort_positions(line1, col1, line2, col2)
if line1 > line2 or line1 == line2 and col1 > col2 then
return line2, col2, line1, col1
end
return line1, col1, line2, col2
end
function Doc:set_selections(idx, line1, col1, line2, col2, swap, rm)
assert(not line2 == not col2, "expected 3 or 5 arguments")
if swap then line1, col1, line2, col2 = line2, col2, line1, col1 end if swap then line1, col1, line2, col2 = line2, col2, line1, col1 end
line1, col1 = self:sanitize_position(line1, col1) line1, col1 = self:sanitize_position(line1, col1)
line2, col2 = self:sanitize_position(line2 or line1, col2 or col1) line2, col2 = self:sanitize_position(line2 or line1, col2 or col1)
self.selection.a.line, self.selection.a.col = line1, col1 common.splice(self.selections, (idx - 1)*4 + 1, rm == nil and 4 or rm, { line1, col1, line2, col2 })
self.selection.b.line, self.selection.b.col = line2, col2
end end
function Doc:add_selection(line1, col1, line2, col2, swap)
local function sort_positions(line1, col1, line2, col2) local l1, c1 = sort_positions(line1, col1, line2 or line1, col2 or col1)
if line1 > line2 local target = #self.selections / 4 + 1
or line1 == line2 and col1 > col2 then for idx, tl1, tc1 in self:get_selections(true) do
return line2, col2, line1, col1, true if l1 < tl1 or l1 == tl1 and c1 < tc1 then
target = idx
break
end
end end
return line1, col1, line2, col2, false self:set_selections(target, line1, col1, line2, col2, swap, 0)
end end
function Doc:set_selection(line1, col1, line2, col2, swap)
self.selections, self.cursor_clipboard = {}, {}
self:set_selections(1, line1, col1, line2, col2, swap)
end
function Doc:get_selection(sort) function Doc:merge_cursors(idx)
local a, b = self.selection.a, self.selection.b for i = (idx or (#self.selections - 3)), (idx or 5), -4 do
if sort then for j = 1, i - 4, 4 do
return sort_positions(a.line, a.col, b.line, b.col) if self.selections[i] == self.selections[j] and
self.selections[i+1] == self.selections[j+1] then
common.splice(self.selections, i, 4)
break
end
end
end end
return a.line, a.col, b.line, b.col
end end
local function selection_iterator(invariant, idx)
function Doc:has_selection() local target = invariant[3] and (idx*4 - 7) or (idx*4 + 1)
local a, b = self.selection.a, self.selection.b if target > #invariant[1] or target <= 0 or (type(invariant[3]) == "number" and invariant[3] ~= idx - 1) then return end
return not (a.line == b.line and a.col == b.col) if invariant[2] then
return idx+(invariant[3] and -1 or 1), sort_positions(unpack(invariant[1], target, target+4))
else
return idx+(invariant[3] and -1 or 1), unpack(invariant[1], target, target+4)
end
end end
-- If idx_reverse is true, it'll reverse iterate. If nil, or false, regular iterate.
function Doc:sanitize_selection() -- If a number, runs for exactly that iteration.
self:set_selection(self:get_selection()) function Doc:get_selections(sort_intra, idx_reverse)
return selection_iterator, { self.selections, sort_intra, idx_reverse },
idx_reverse == true and ((#self.selections / 4) + 1) or ((idx_reverse or -1)+1)
end end
-- End of cursor seciton.
function Doc:sanitize_position(line, col) function Doc:sanitize_position(line, col)
line = common.clamp(line, 1, #self.lines) line = common.clamp(line, 1, #self.lines)
@ -251,14 +274,11 @@ local function pop_undo(self, undo_stack, redo_stack, modified)
if cmd.type == "insert" then if cmd.type == "insert" then
local line, col, text = table.unpack(cmd) local line, col, text = table.unpack(cmd)
self:raw_insert(line, col, text, redo_stack, cmd.time) self:raw_insert(line, col, text, redo_stack, cmd.time)
elseif cmd.type == "remove" then elseif cmd.type == "remove" then
local line1, col1, line2, col2 = table.unpack(cmd) local line1, col1, line2, col2 = table.unpack(cmd)
self:raw_remove(line1, col1, line2, col2, redo_stack, cmd.time) self:raw_remove(line1, col1, line2, col2, redo_stack, cmd.time)
elseif cmd.type == "selection" then elseif cmd.type == "selection" then
self.selection.a.line, self.selection.a.col = cmd[1], cmd[2] self.selections = { unpack(cmd) }
self.selection.b.line, self.selection.b.col = cmd[3], cmd[4]
end end
modified = modified or (cmd.type ~= "selection") modified = modified or (cmd.type ~= "selection")
@ -288,11 +308,11 @@ function Doc:raw_insert(line, col, text, undo_stack, time)
lines[#lines] = lines[#lines] .. after lines[#lines] = lines[#lines] .. after
-- splice lines into line array -- splice lines into line array
splice(self.lines, line, 1, lines) common.splice(self.lines, line, 1, lines)
-- push undo -- push undo
local line2, col2 = self:position_offset(line, col, #text) local line2, col2 = self:position_offset(line, col, #text)
push_undo(undo_stack, time, "selection", self:get_selection()) push_undo(undo_stack, time, "selection", unpack(self.selections))
push_undo(undo_stack, time, "remove", line, col, line2, col2) push_undo(undo_stack, time, "remove", line, col, line2, col2)
-- update highlighter and assure selection is in bounds -- update highlighter and assure selection is in bounds
@ -304,7 +324,7 @@ end
function Doc:raw_remove(line1, col1, line2, col2, undo_stack, time) function Doc:raw_remove(line1, col1, line2, col2, undo_stack, time)
-- push undo -- push undo
local text = self:get_text(line1, col1, line2, col2) local text = self:get_text(line1, col1, line2, col2)
push_undo(undo_stack, time, "selection", self:get_selection()) push_undo(undo_stack, time, "selection", unpack(self.selections))
push_undo(undo_stack, time, "insert", line1, col1, text) push_undo(undo_stack, time, "insert", line1, col1, text)
-- get line content before/after removed text -- get line content before/after removed text
@ -312,7 +332,7 @@ function Doc:raw_remove(line1, col1, line2, col2, undo_stack, time)
local after = self.lines[line2]:sub(col2) local after = self.lines[line2]:sub(col2)
-- splice line into line array -- splice line into line array
splice(self.lines, line1, line2 - line1 + 1, { before .. after }) common.splice(self.lines, line1, line2 - line1 + 1, { before .. after })
-- update highlighter and assure selection is in bounds -- update highlighter and assure selection is in bounds
self.highlighter:invalidate(line1) self.highlighter:invalidate(line1)
@ -348,22 +368,20 @@ function Doc:redo()
end end
function Doc:text_input(text) function Doc:text_input(text, idx)
if self:has_selection() then for sidx, line1, col1, line2, col2 in self:get_selections(true, idx) do
self:delete_to() if line1 ~= line2 or col1 ~= col2 then
self:delete_to_cursor(sidx)
end
self:insert(line1, col1, text)
self:move_to_cursor(sidx, #text)
end end
local line, col = self:get_selection()
self:insert(line, col, text)
self:move_to(#text)
end end
function Doc:replace(fn) function Doc:replace(fn)
local line1, col1, line2, col2, swap local line1, col1, line2, col2 = self:get_selection(true)
local had_selection = self:has_selection() if line1 == line2 and col1 == col2 then
if had_selection then
line1, col1, line2, col2, swap = self:get_selection(true)
else
line1, col1, line2, col2 = 1, 1, #self.lines, #self.lines[#self.lines] line1, col1, line2, col2 = 1, 1, #self.lines, #self.lines[#self.lines]
end end
local old_text = self:get_text(line1, col1, line2, col2) local old_text = self:get_text(line1, col1, line2, col2)
@ -371,38 +389,104 @@ function Doc:replace(fn)
if old_text ~= new_text then if old_text ~= new_text then
self:insert(line2, col2, new_text) self:insert(line2, col2, new_text)
self:remove(line1, col1, line2, col2) self:remove(line1, col1, line2, col2)
if had_selection then if line1 == line2 and col1 == col2 then
line2, col2 = self:position_offset(line1, col1, #new_text) line2, col2 = self:position_offset(line1, col1, #new_text)
self:set_selection(line1, col1, line2, col2, swap) self:set_selection(line1, col1, line2, col2)
end end
end end
return n return n
end end
function Doc:delete_to(...) function Doc:delete_to_cursor(idx, ...)
local line, col = self:get_selection(true) for sidx, line1, col1, line2, col2 in self:get_selections(true, idx) do
if self:has_selection() then if line1 ~= line2 or col1 ~= col2 then
self:remove(self:get_selection()) self:remove(line1, col1, line2, col2)
else else
local line2, col2 = self:position_offset(line, col, ...) local l2, c2 = self:position_offset(line1, col1, ...)
self:remove(line, col, line2, col2) self:remove(line1, col1, l2, c2)
line, col = sort_positions(line, col, line2, col2) line1, col1 = sort_positions(line1, col1, l2, c2)
end
self:set_selections(sidx, line1, col1)
end end
self:set_selection(line, col) self:merge_cursors(idx)
end
function Doc:delete_to(...) return self:delete_to_cursor(nil, ...) end
function Doc:move_to_cursor(idx, ...)
for sidx, line, col in self:get_selections(false, idx) do
self:set_selections(sidx, self:position_offset(line, col, ...))
end
self:merge_cursors(idx)
end
function Doc:move_to(...) return self:move_to_cursor(nil, ...) end
function Doc:select_to_cursor(idx, ...)
for sidx, line, col, line2, col2 in self:get_selections(false, idx) do
line, col = self:position_offset(line, col, ...)
self:set_selections(sidx, line, col, line2, col2)
end
self:merge_cursors(idx)
end
function Doc:select_to(...) return self:select_to_cursor(nil, ...) end
local function get_indent_string()
if config.tab_type == "hard" then
return "\t"
end
return string.rep(" ", config.indent_size)
end end
-- returns the size of the original indent, and the indent
function Doc:move_to(...) -- in your config format, rounded either up or down
local line, col = self:get_selection() local function get_line_indent(line, rnd_up)
self:set_selection(self:position_offset(line, col, ...)) local _, e = line:find("^[ \t]+")
local soft_tab = string.rep(" ", config.indent_size)
if config.tab_type == "hard" then
local indent = e and line:sub(1, e):gsub(soft_tab, "\t") or ""
return e, indent:gsub(" +", rnd_up and "\t" or "")
else
local indent = e and line:sub(1, e):gsub("\t", soft_tab) or ""
local number = #indent / #soft_tab
return e, indent:sub(1,
(rnd_up and math.ceil(number) or math.floor(number))*#soft_tab)
end
end end
-- un/indents text; behaviour varies based on selection and un/indent.
function Doc:select_to(...) -- * if there's a selection, it will stay static around the
local line, col, line2, col2 = self:get_selection() -- text for both indenting and unindenting.
line, col = self:position_offset(line, col, ...) -- * if you are in the beginning whitespace of a line, and are indenting, the
self:set_selection(line, col, line2, col2) -- cursor will insert the exactly appropriate amount of spaces, and jump the
-- cursor to the beginning of first non whitespace characters
-- * if you are not in the beginning whitespace of a line, and you indent, it
-- inserts the appropriate whitespace, as if you typed them normally.
-- * if you are unindenting, the cursor will jump to the start of the line,
-- and remove the appropriate amount of spaces (or a tab).
function Doc:indent_text(unindent, line1, col1, line2, col2)
local text = get_indent_string()
local _, se = self.lines[line1]:find("^[ \t]+")
local in_beginning_whitespace = col1 == 1 or (se and col1 <= se + 1)
local has_selection = line1 ~= line2 or col1 ~= col2
if unindent or has_selection or in_beginning_whitespace then
local l1d, l2d = #self.lines[line1], #self.lines[line2]
for line = line1, line2 do
local e, rnded = get_line_indent(self.lines[line], unindent)
self:remove(line, 1, line, (e or 0) + 1)
self:insert(line, 1,
unindent and rnded:sub(1, #rnded - #text) or rnded .. text)
end
l1d, l2d = #self.lines[line1] - l1d, #self.lines[line2] - l2d
if (unindent or in_beginning_whitespace) and not has_selection then
local start_cursor = (se and se + 1 or 1) + l1d or #(self.lines[line1])
return line1, start_cursor, line2, start_cursor
end
return line1, col1 + l1d, line2, col2 + l2d
end
self:insert(line1, col1, text)
return line1, col1 + #text, line1, col1 + #text
end end
-- For plugins to add custom actions of document change -- For plugins to add custom actions of document change

0
data/core/doc/search.lua Normal file → Executable file
View File

0
data/core/doc/translate.lua Normal file → Executable file
View File

View File

@ -96,7 +96,10 @@ function DocView:get_filename()
end end
function DocView:get_scrollable_size() function DocView:get_scrollable_size()
if not config.scroll_past_end then
return self:get_line_height() * (#self.doc.lines) + style.padding.y * 2
end
return self:get_line_height() * (#self.doc.lines - 1) + self.size.y return self:get_line_height() * (#self.doc.lines - 1) + self.size.y
end end
@ -256,7 +259,11 @@ function DocView:on_mouse_pressed(button, x, y, clicks)
end end
else else
local line, col = self:resolve_screen_position(x, y) local line, col = self:resolve_screen_position(x, y)
self.doc:set_selection(mouse_selection(self.doc, clicks, line, col, line, col)) if keymap.modkeys["ctrl"] then
self.doc:add_selection(mouse_selection(self.doc, clicks, line, col, line, col))
else
self.doc:set_selection(mouse_selection(self.doc, clicks, line, col, line, col))
end
self.mouse_selecting = { line, col, clicks = clicks } self.mouse_selecting = { line, col, clicks = clicks }
end end
core.blink_reset() core.blink_reset()
@ -276,7 +283,15 @@ function DocView:on_mouse_moved(x, y, ...)
local l1, c1 = self:resolve_screen_position(x, y) local l1, c1 = self:resolve_screen_position(x, y)
local l2, c2 = table.unpack(self.mouse_selecting) local l2, c2 = table.unpack(self.mouse_selecting)
local clicks = self.mouse_selecting.clicks local clicks = self.mouse_selecting.clicks
self.doc:set_selection(mouse_selection(self.doc, clicks, l1, c1, l2, c2)) if keymap.modkeys["ctrl"] then
if l1 > l2 then l1, l2 = l2, l1 end
self.doc.selections = { }
for i = l1, l2 do
self.doc:set_selections(i - l1 + 1, i, math.min(c1, #self.doc.lines[i]), i, math.min(c2, #self.doc.lines[i]))
end
else
self.doc:set_selection(mouse_selection(self.doc, clicks, l1, c1, l2, c2))
end
end end
end end
@ -340,46 +355,50 @@ end
function DocView:draw_line_body(idx, x, y) function DocView:draw_line_body(idx, x, y)
local line, col = self.doc:get_selection()
-- draw selection if it overlaps this line -- draw selection if it overlaps this line
local line1, col1, line2, col2 = self.doc:get_selection(true) for lidx, line1, col1, line2, col2 in self.doc:get_selections(true) do
if idx >= line1 and idx <= line2 then if idx >= line1 and idx <= line2 then
local text = self.doc.lines[idx] local text = self.doc.lines[idx]
if line1 ~= idx then col1 = 1 end if line1 ~= idx then col1 = 1 end
if line2 ~= idx then col2 = #text + 1 end if line2 ~= idx then col2 = #text + 1 end
local x1 = x + self:get_col_x_offset(idx, col1) local x1 = x + self:get_col_x_offset(idx, col1)
local x2 = x + self:get_col_x_offset(idx, col2) local x2 = x + self:get_col_x_offset(idx, col2)
local lh = self:get_line_height() local lh = self:get_line_height()
renderer.draw_rect(x1, y, x2 - x1, lh, style.selection) renderer.draw_rect(x1, y, x2 - x1, lh, style.selection)
end
end end
for lidx, line1, col1, line2, col2 in self.doc:get_selections(true) do
-- draw line highlight if caret is on this line -- draw line highlight if caret is on this line
if config.highlight_current_line and not self.doc:has_selection() if config.highlight_current_line and (line1 == line2 and col1 == col2)
and line == idx and core.active_view == self then and line1 == idx and core.active_view == self then
self:draw_line_highlight(x + self.scroll.x, y) self:draw_line_highlight(x + self.scroll.x, y)
end
end end
-- draw line's text -- draw line's text
self:draw_line_text(idx, x, y) self:draw_line_text(idx, x, y)
-- draw caret if it overlaps this line -- draw caret if it overlaps this line
local T = config.blink_period local T = config.blink_period
if line == idx and core.active_view == self for _, line, col in self.doc:get_selections() do
and (core.blink_timer - core.blink_start) % T < T / 2 if line == idx and core.active_view == self
and system.window_has_focus() then and (core.blink_timer - core.blink_start) % T < T / 2
local lh = self:get_line_height() and system.window_has_focus() then
local x1 = x + self:get_col_x_offset(line, col) local lh = self:get_line_height()
renderer.draw_rect(x1, y, style.caret_width, lh, style.caret) local x1 = x + self:get_col_x_offset(line, col)
renderer.draw_rect(x1, y, style.caret_width, lh, style.caret)
end
end end
end end
function DocView:draw_line_gutter(idx, x, y) function DocView:draw_line_gutter(idx, x, y)
local color = style.line_number local color = style.line_number
local line1, _, line2, _ = self.doc:get_selection(true) for _, line1, _, line2 in self.doc:get_selections(true) do
if idx >= line1 and idx <= line2 then if idx >= line1 and idx <= line2 then
color = style.line_number2 color = style.line_number2
break
end
end end
local yoffset = self:get_line_text_y_offset() local yoffset = self:get_line_text_y_offset()
x = x + style.padding.x x = x + style.padding.x

View File

@ -59,9 +59,9 @@ end
function core.reschedule_project_scan() function core.reschedule_project_scan()
if core.project_scan_thread_id then -- if core.project_scan_thread_id then
core.threads[core.project_scan_thread_id].wake = 0 -- core.threads[core.project_scan_thread_id].wake = 0
end -- end
end end
@ -512,6 +512,7 @@ function core.init()
core.redraw = true core.redraw = true
core.visited_files = {} core.visited_files = {}
core.restart_request = false core.restart_request = false
core.quite_request = false
core.replacements = whitespace_replacements() core.replacements = whitespace_replacements()
core.root_view = RootView() core.root_view = RootView()
@ -535,7 +536,7 @@ function core.init()
local plugins_success, plugins_refuse_list = core.load_plugins() local plugins_success, plugins_refuse_list = core.load_plugins()
do do
local pdir, pname = project_dir_abs:match("(.*)[/\\\\](.*)") local pdir, pname = project_dir_abs:match("(.*)[:/\\\\](.*)")
core.log("Opening project %q from directory %s", pname, pdir) core.log("Opening project %q from directory %s", pname, pdir)
end end
local got_project_error = not core.load_project_module() local got_project_error = not core.load_project_module()
@ -668,7 +669,8 @@ local function quit_with_function(quit_fn, force)
end end
function core.quit(force) function core.quit(force)
quit_with_function(os.exit, force) -- quit_with_function(os.exit, force)
quit_with_function(function() core.quit_request = true end, force)
end end
@ -1044,7 +1046,7 @@ function core.run()
core.frame_start = system.get_time() core.frame_start = system.get_time()
local did_redraw = core.step() local did_redraw = core.step()
local need_more_work = run_threads() local need_more_work = run_threads()
if core.restart_request then break end if core.restart_request or core.quit_request then break end
if not did_redraw and not need_more_work then if not did_redraw and not need_more_work then
idle_iterations = idle_iterations + 1 idle_iterations = idle_iterations + 1
-- do not wait of events at idle_iterations = 1 to give a chance at core.step to run -- do not wait of events at idle_iterations = 1 to give a chance at core.step to run

2
data/core/keymap-macos.lua Normal file → Executable file
View File

@ -101,6 +101,8 @@ local function keymap_macos(keymap)
["cmd+shift+end"] = "doc:select-to-end-of-doc", ["cmd+shift+end"] = "doc:select-to-end-of-doc",
["shift+pageup"] = "doc:select-to-previous-page", ["shift+pageup"] = "doc:select-to-previous-page",
["shift+pagedown"] = "doc:select-to-next-page", ["shift+pagedown"] = "doc:select-to-next-page",
["cmd+shift+up"] = "doc:create-cursor-previous-line",
["cmd+shift+down"] = "doc:create-cursor-next-line"
} }
end end

View File

@ -6,9 +6,12 @@ keymap.map = {}
keymap.reverse_map = {} keymap.reverse_map = {}
local macos = rawget(_G, "MACOS_RESOURCES") local macos = rawget(_G, "MACOS_RESOURCES")
local os4 = false
if PLATFORM == "AmigaOS 4" then
os4 = true
end
-- Thanks to mathewmariani, taken from his lite-macos github repository. -- Thanks to mathewmariani, taken from his lite-macos github repository.
local modkeys_os = require("core.modkeys-" .. (macos and "macos" or "generic")) local modkeys_os = require("core.modkeys-" .. (macos and "macos" or os4 and "os4" or "generic"))
local modkey_map = modkeys_os.map local modkey_map = modkeys_os.map
local modkeys = modkeys_os.keys local modkeys = modkeys_os.keys
@ -202,6 +205,8 @@ keymap.add_direct {
["ctrl+shift+end"] = "doc:select-to-end-of-doc", ["ctrl+shift+end"] = "doc:select-to-end-of-doc",
["shift+pageup"] = "doc:select-to-previous-page", ["shift+pageup"] = "doc:select-to-previous-page",
["shift+pagedown"] = "doc:select-to-next-page", ["shift+pagedown"] = "doc:select-to-next-page",
["ctrl+shift+up"] = "doc:create-cursor-previous-line",
["ctrl+shift+down"] = "doc:create-cursor-next-line"
} }
return keymap return keymap

0
data/core/logview.lua Normal file → Executable file
View File

0
data/core/modkeys-generic.lua Normal file → Executable file
View File

0
data/core/modkeys-macos.lua Normal file → Executable file
View File

15
data/core/modkeys-os4.lua Executable file
View File

@ -0,0 +1,15 @@
local modkeys = {}
modkeys.map = {
["left amiga"] = "cmd",
["right amiga"] = "cmd",
["control"] = "ctrl",
["left shift"] = "shift",
["right shift"] = "shift",
["left alt"] = "alt",
["right alt"] = "altgr",
}
modkeys.keys = { "cmd", "ctrl", "alt", "altgr", "shift" }
return modkeys

0
data/core/nagview.lua Normal file → Executable file
View File

0
data/core/object.lua Normal file → Executable file
View File

0
data/core/rootview.lua Normal file → Executable file
View File

0
data/core/start.lua Normal file → Executable file
View File

0
data/core/statusview.lua Normal file → Executable file
View File

0
data/core/strict.lua Normal file → Executable file
View File

0
data/core/style.lua Normal file → Executable file
View File

0
data/core/syntax.lua Normal file → Executable file
View File

0
data/core/titleview.lua Normal file → Executable file
View File

0
data/core/tokenizer.lua Normal file → Executable file
View File

0
data/core/view.lua Normal file → Executable file
View File

0
data/fonts/FiraSans-Regular.ttf Normal file → Executable file
View File

0
data/fonts/JetBrainsMono-Regular.ttf Normal file → Executable file
View File

0
data/fonts/icons.ttf Normal file → Executable file
View File

0
data/plugins/autocomplete.lua Normal file → Executable file
View File

0
data/plugins/autoreload.lua Normal file → Executable file
View File

0
data/plugins/detectindent.lua Normal file → Executable file
View File

0
data/plugins/language_c.lua Normal file → Executable file
View File

0
data/plugins/language_cpp.lua Normal file → Executable file
View File

0
data/plugins/language_css.lua Normal file → Executable file
View File

0
data/plugins/language_html.lua Normal file → Executable file
View File

0
data/plugins/language_js.lua Normal file → Executable file
View File

0
data/plugins/language_lua.lua Normal file → Executable file
View File

0
data/plugins/language_md.lua Normal file → Executable file
View File

0
data/plugins/language_python.lua Normal file → Executable file
View File

0
data/plugins/language_xml.lua Normal file → Executable file
View File

0
data/plugins/macro.lua Normal file → Executable file
View File

0
data/plugins/projectsearch.lua Normal file → Executable file
View File

0
data/plugins/quote.lua Normal file → Executable file
View File

0
data/plugins/reflow.lua Normal file → Executable file
View File

0
data/plugins/tabularize.lua Normal file → Executable file
View File

0
data/plugins/toolbarview.lua Normal file → Executable file
View File

0
data/plugins/treeview.lua Normal file → Executable file
View File

0
data/plugins/trimwhitespace.lua Normal file → Executable file
View File

0
data/plugins/workspace.lua Normal file → Executable file
View File

14
lib/font_renderer/os4build.sh Executable file
View File

@ -0,0 +1,14 @@
#!/bin/bash
cxxcompiler="g++"
cxxflags="-Wall -O3 -g -std=c++03 -fno-exceptions -fno-rtti -Isrc -Ilib/font_renderer -DFONT_RENDERER_HEIGHT_HACK -lagg -lfreetype -I/sdk/local/common/include/agg"
echo "compiling font renderer library..."
g++ -c $cxxflags agg_font_freetype.cpp -o agg_font_freetype.o
g++ -c $cxxflags font_renderer.cpp -o font_renderer.o
ar -rcs libfontrenderer.a *.o
rm *.o
echo "font renderer library created"

BIN
lite.info Normal file

Binary file not shown.

46
os4build.sh Normal file
View File

@ -0,0 +1,46 @@
#!/bin/bash
cflags="-D__USE_INLINE__ -DLITE_XL_DATA_USE_EXEDIR -DLITE_USE_SDL_RENDERER -Wall -O3 -std=gnu11 -fno-strict-aliasing -Isrc -Ilib/font_renderer -I/sdk/local/newlib/include/SDL2 -lSDL2 -llua -lauto"
#cflags+=" $(pkg-config --cflags lua5.2) $(sdl2-config --cflags)"
lflags="-mcrt=newlib -static-libgcc -static-libstdc++ -lSDL2 -lagg -lfreetype -llua -lm -lpthread -athread=native"
#for package in libagg freetype2 lua5.2; do
# lflags+=" $(pkg-config --libs $package)"
#done
#lflags+=" $(sdl2-config --libs) -lm"
#if [[ $* == *windows* ]]; then
# echo "cross compiling for windows is not yet supported"
# exit 1
#else
outfile="lite"
compiler="gcc"
cxxcompiler="g++"
#fi
#lib/font_renderer/build.sh || exit 1
#libs=libfontrenderer.a
libs="-lfontrenderer"
echo "compiling lite..."
gcc -c $cflags src/fontdesc.c -o fontdesc.o
gcc -c $cflags src/main.c -o main.o
gcc -c $cflags src/rencache.c -o rencache.o
gcc -c $cflags src/renderer.c -o renderer.o
gcc -c $cflags src/renwindow.c -o renwindow.o
gcc -c $cflags src/api/api.c -o api.o
gcc -c $cflags src/api/cp_replace.c -o cp_replace.o
gcc -c $cflags src/api/renderer.c -o apirenderer.o
gcc -c $cflags src/api/renderer_font.c -o renderer_font.o
gcc -c $cflags src/api/system.c -o system.o
gcc -c $cflags src/platform/amigaos4.c -o amigaos4.o
echo "linking..."
g++ -o $outfile *.o $libs $lflags
echo "cleaning up..."
rm *.o
echo "done"

BIN
release_files/LiteXL.info Normal file

Binary file not shown.

Binary file not shown.

BIN
release_files/lite.info Normal file

Binary file not shown.

0
src/api/api.c Normal file → Executable file
View File

0
src/api/api.h Normal file → Executable file
View File

0
src/api/cp_replace.c Normal file → Executable file
View File

0
src/api/renderer.c Normal file → Executable file
View File

0
src/api/renderer_font.c Normal file → Executable file
View File

View File

@ -12,6 +12,10 @@
#include <windows.h> #include <windows.h>
#endif #endif
#ifdef __amigaos4__
#include "platform/amigaos4.h"
#endif
extern SDL_Window *window; extern SDL_Window *window;
@ -287,7 +291,11 @@ static int f_set_window_mode(lua_State *L) {
int n = luaL_checkoption(L, 1, "normal", window_opts); int n = luaL_checkoption(L, 1, "normal", window_opts);
SDL_SetWindowFullscreen(window, SDL_SetWindowFullscreen(window,
n == WIN_FULLSCREEN ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); n == WIN_FULLSCREEN ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
if (n == WIN_NORMAL) { SDL_RestoreWindow(window); } if (n == WIN_NORMAL)
{
ren_resize_window();
SDL_RestoreWindow(window);
}
if (n == WIN_MAXIMIZED) { SDL_MaximizeWindow(window); } if (n == WIN_MAXIMIZED) { SDL_MaximizeWindow(window); }
if (n == WIN_MINIMIZED) { SDL_MinimizeWindow(window); } if (n == WIN_MINIMIZED) { SDL_MinimizeWindow(window); }
return 0; return 0;
@ -423,6 +431,10 @@ static int f_list_dir(lua_State *L) {
#define realpath(x, y) _fullpath(y, x, MAX_PATH) #define realpath(x, y) _fullpath(y, x, MAX_PATH)
#endif #endif
#ifdef __amigaos4__
#define realpath(x, y) _fullpath(x)
#endif
static int f_absolute_path(lua_State *L) { static int f_absolute_path(lua_State *L) {
const char *path = luaL_checkstring(L, 1); const char *path = luaL_checkstring(L, 1);
char *res = realpath(path, NULL); char *res = realpath(path, NULL);

0
src/bundle_open.m Normal file → Executable file
View File

0
src/fontdesc.c Normal file → Executable file
View File

0
src/fontdesc.h Normal file → Executable file
View File

View File

@ -13,6 +13,8 @@
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <X11/Xresource.h> #include <X11/Xresource.h>
#elif __amigaos4__
#include "platform/amigaos4.h"
#elif __APPLE__ #elif __APPLE__
#include <mach-o/dyld.h> #include <mach-o/dyld.h>
#endif #endif
@ -70,12 +72,13 @@ static void get_exe_filename(char *buf, int sz) {
char exepath[size]; char exepath[size];
_NSGetExecutablePath(exepath, &size); _NSGetExecutablePath(exepath, &size);
realpath(exepath, buf); realpath(exepath, buf);
#elif __amigaos4__
strcpy(buf, _fullpath("./lite"));
#else #else
strcpy(buf, "./lite"); strcpy(buf, "./lite");
#endif #endif
} }
static void init_window_icon(void) { static void init_window_icon(void) {
#ifndef _WIN32 #ifndef _WIN32
#include "../icon.inl" #include "../icon.inl"
@ -132,6 +135,8 @@ int main(int argc, char **argv) {
window = SDL_CreateWindow( window = SDL_CreateWindow(
"", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, dm.w * 0.8, dm.h * 0.8, "", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, dm.w * 0.8, dm.h * 0.8,
SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN); SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN);
SDL_SetWindowDisplayMode(window, &dm);
init_window_icon(); init_window_icon();
ren_init(window); ren_init(window);
@ -154,7 +159,6 @@ init_lua:
lua_pushnumber(L, get_scale()); lua_pushnumber(L, get_scale());
lua_setglobal(L, "SCALE"); lua_setglobal(L, "SCALE");
char exename[2048]; char exename[2048];
get_exe_filename(exename, sizeof(exename)); get_exe_filename(exename, sizeof(exename));
lua_pushstring(L, exename); lua_pushstring(L, exename);
@ -164,13 +168,15 @@ init_lua:
set_macos_bundle_resources(L); set_macos_bundle_resources(L);
enable_momentum_scroll(); enable_momentum_scroll();
#endif #endif
const char *init_lite_code = \ const char *init_lite_code = \
"local core\n" "local core\n"
"xpcall(function()\n" "xpcall(function()\n"
" HOME = os.getenv('" LITE_OS_HOME "')\n" " HOME = os.getenv('" LITE_OS_HOME "')\n"
" local exedir = EXEFILE:match(\"^(.*)" LITE_PATHSEP_PATTERN LITE_NONPATHSEP_PATTERN "$\")\n" " local exedir = EXEFILE:match(\"^(.*)" LITE_PATHSEP_PATTERN LITE_NONPATHSEP_PATTERN "$\")\n"
" local prefix = exedir:match(\"^(.*)" LITE_PATHSEP_PATTERN "bin$\")\n" " local prefix = exedir:match(\"^(.*)" LITE_PATHSEP_PATTERN "bin$\")\n"
" if not HOME then\n"
" HOME = exedir\n"
" end\n"
" dofile((MACOS_RESOURCES or (prefix and prefix .. '/share/lite-xl' or exedir .. '/data')) .. '/core/start.lua')\n" " dofile((MACOS_RESOURCES or (prefix and prefix .. '/share/lite-xl' or exedir .. '/data')) .. '/core/start.lua')\n"
" core = require('core')\n" " core = require('core')\n"
" core.init()\n" " core.init()\n"
@ -203,11 +209,12 @@ init_lua:
lua_pcall(L, 0, 1, 0); lua_pcall(L, 0, 1, 0);
if (lua_toboolean(L, -1)) { if (lua_toboolean(L, -1)) {
lua_close(L); lua_close(L);
rencache_invalidate();
goto init_lua; goto init_lua;
} }
lua_close(L); lua_close(L);
ren_free_window_resources(); ren_free_window_resources();
SDL_Quit();
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

0
src/meson.build Normal file → Executable file
View File

61
src/platform/amigaos4.c Normal file
View File

@ -0,0 +1,61 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "amigaos4.h"
static char *getFullPath(const char *path)
{
char *appPath = malloc(sizeof(char) * MAX_DOS_NAME);
BPTR pathLock = Lock(path, SHARED_LOCK);
if (pathLock)
{
NameFromLock(pathLock, appPath, sizeof(char) * MAX_DOS_NAME);
UnLock(pathLock);
return appPath;
}
return NULL;
}
static char *getCurrentPath(void)
{
char *appPath = malloc(sizeof(char) * MAX_DOS_NAME);
BPTR pathLock = GetCurrentDir();
if (pathLock)
{
NameFromLock(pathLock, appPath, sizeof(char) * MAX_DOS_NAME);
return appPath;
}
return NULL;
}
char *_fullpath(const char *path)
{
static char prvPath[MAX_DOS_NAME];
static char result[MAX_DOS_NAME];
if (!strcmp(path, prvPath))
{
return result;
}
strcpy(prvPath, path);
if (!strcmp(path, "./lite"))
{
// TODO: Add code to get the name of the executable
strcpy(result, getFullPath("PROGDIR:lite"));
return result;
}
if (!strcmp(path, "."))
{
strcpy(result, getCurrentPath());
return result;
}
strcpy(result, getFullPath(path));
return result;
}

16
src/platform/amigaos4.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef _AMIGAOS4_H
#define _AMIGAOS4_H
#include <proto/dos.h>
#include <proto/exec.h>
#define VSTRING "Lite XL 1.16.12.6 (04.01.2022)"
#define VERSTAG "\0$VER: " VSTRING
static CONST_STRPTR stack USED = "$STACK:102400";
static CONST_STRPTR version USED = VERSTAG;
char *_fullpath(const char *);
#endif

0
src/rencache.c Normal file → Executable file
View File

0
src/rencache.h Normal file → Executable file
View File

0
src/renderer.c Normal file → Executable file
View File

0
src/renderer.h Normal file → Executable file
View File

View File

@ -9,6 +9,15 @@ static int query_surface_scale(RenWindow *ren) {
SDL_GetWindowSize(ren->window, &w_points, &h_points); SDL_GetWindowSize(ren->window, &w_points, &h_points);
/* We consider that the ratio pixel/point will always be an integer and /* We consider that the ratio pixel/point will always be an integer and
it is the same along the x and the y axis. */ it is the same along the x and the y axis. */
// This is a workaround when the w_pixels != w_points and h_pixels != h_points
// because of redraw delays, especially when the "Resize with contents" is enabled
if (w_pixels != w_points) {
w_pixels = w_points;
}
if (h_pixels != h_points) {
h_pixels = h_points;
}
assert(w_pixels % w_points == 0 && h_pixels % h_points == 0 && w_pixels / w_points == h_pixels / h_points); assert(w_pixels % w_points == 0 && h_pixels % h_points == 0 && w_pixels / w_points == h_pixels / h_points);
return w_pixels / w_points; return w_pixels / w_points;
} }
@ -20,7 +29,7 @@ static void setup_renderer(RenWindow *ren, int w, int h) {
SDL_DestroyTexture(ren->texture); SDL_DestroyTexture(ren->texture);
SDL_DestroyRenderer(ren->renderer); SDL_DestroyRenderer(ren->renderer);
} }
ren->renderer = SDL_CreateRenderer(ren->window, -1, 0); ren->renderer = SDL_CreateRenderer(ren->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
ren->texture = SDL_CreateTexture(ren->renderer, SDL_PIXELFORMAT_BGRA32, SDL_TEXTUREACCESS_STREAMING, w, h); ren->texture = SDL_CreateTexture(ren->renderer, SDL_PIXELFORMAT_BGRA32, SDL_TEXTUREACCESS_STREAMING, w, h);
ren->surface_scale = query_surface_scale(ren); ren->surface_scale = query_surface_scale(ren);
} }

0
src/renwindow.h Normal file → Executable file
View File