Compare commits

...

7 Commits

Author SHA1 Message Date
George Sokianos ab72e26080 Fixes to make the 2.1 branch working on OS4 - WIP 2022-04-04 11:31:17 +01:00
George Sokianos aa14bd6a88 Applied all the necessary changes to make it run under AmigaOS 4.1 FE 2022-03-27 22:57:25 +01:00
Adam Harrison 7a78b780f4 Apparenlty these were issues? What? 2022-03-24 20:12:45 -04:00
Adam Harrison a9f5e73044 Merge branch 'master-2.1' of github.com:lite-xl/lite-xl into master-2.1 2022-03-24 12:46:48 -04:00
Adam Harrison 0873da9670 Added in notes to the changelog. 2022-03-24 12:46:38 -04:00
Adam a8b97dffab
Soft Line Wrapping (#636)
Added in soft line wrapping.
2022-03-24 12:01:46 -04:00
Adam Harrison a0194ac26b Bumping version numbers. 2022-03-24 11:57:26 -04:00
49 changed files with 1212 additions and 197 deletions

5
.gitignore vendored
View File

@ -17,3 +17,8 @@ compile_commands.json
error.txt
lite-xl*
LiteXL*
lite
.config/
*.lha
release_files
*.o

85
Makefile.os4 Normal file
View File

@ -0,0 +1,85 @@
#
# Project: Lite XL
#
# Created on: 26-12-2021
#
LiteXL_OBJ := \
src/main.o src/rencache.o src/renderer.o src/renwindow.o \
src/api/dirmonitor/os4.o \
src/api/api.o src/api/dirmonitor.o src/api/regex.o \
src/api/renderer.o src/api/system.o \
src/platform/amigaos4.o
# src/api/process.o
outfile := lite
compiler := gcc
cxxcompiler := g++
INCPATH := -Isrc -Ilib/dmon -I/sdk/local/newlib/include/SDL2 -I/sdk/local/common/include/freetype2
DFLAGS := -D__USE_INLINE__ -DLITE_XL_DATA_USE_EXEDIR -DDIRMONITOR_BACKEND=os4 -DDIRMONITOR_OS4
# -DLITE_USE_SDL_RENDERER
# -Wextra -Wall
CFLAGS := -Werror -Wwrite-strings -O3 -g -std=gnu11 -fno-strict-aliasing
# "-gstabs -finstrument-functions -fno-inline -DPROFILING"
LFLAGS := -mcrt=newlib -static-libgcc -static-libstdc++ -lauto -lpcre2 -lSDL2 -llua -lagg -lfreetype -lm -lunix -lpthread -athread=native
# " -lprofyle"
.PHONY: LiteXL clean release
default: LiteXL
clean:
@echo "Cleaning compiler objects..."
@rm -f $(LiteXL_OBJ)
LiteXL: $(LiteXL_OBJ)
@echo "Linking LiteXL"
@$(cxxcompiler) -o $(outfile) $(LiteXL_OBJ) $(LFLAGS)
.c.o:
@echo "Compiling $<"
@$(compiler) -c $< -o $*.o $(CFLAGS) $(INCPATH) $(DFLAGS)
src/main.o: src/main.c src/api/api.h src/rencache.h \
src/renderer.h src/platform/amigaos4.h
src/rencache.o: src/rencache.c
src/renderer.o: src/renderer.c
src/renwindow.o: src/renwindow.c
src/api/dirmonitor/os4.o: src/api/dirmonitor/os4.c
src/api/api.o: src/api/api.c
src/api/dirmonitor.o: src/api/dirmonitor.c src/api/dirmonitor/os4.c
src/api/regex.o: src/api/regex.c
src/api/renderer.o: src/api/renderer.c
src/api/system.o: src/api/system.c
src/platform/amigaos4.o: src/platform/amigaos4.c
release:
mkdir -p release/LiteXL
cp release_files/* release/LiteXL/ -r
mv release/LiteXL/LiteXL.info release/
cp data release/LiteXL/ -r
cp changelog.md release/LiteXL/
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/

169
README_OS4.md Normal file
View File

@ -0,0 +1,169 @@
# Lite XL v2.1 for AmigaOS 4.1 FE
Lite XL is a lightweight text editor written in Lua.
## 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/"
```
## Addons
### Colors
Colors are lua files that set the color scheme of the editor. There are
light and dark themes for you to choose.
To install and use them you have to copy the ones you would like from
`addons/colors/light` or `addons/colors/dark` into the folder
`.config/lite-xl/colors/`. Don't add light or dark folders. Just copy the
.lua files in there.
Then you have to start Lite XL and open your configuration by clicking
at the cog icon at the toolbar (bottom left sixth icon). Go at the line
that looks like below
```
-- core.reload_module("colors.summer")
```
and change the `summer` with the name of your color theme. Also, remove
the two dashes `--` at the start of the line and save the file. If you
did everything right, the color schema should change instantly.
The themes can also be found at
https://github.com/lite-xl/lite-xl-colors
### Plugins
The Lite XL that you are using on AmigaOS 4 is based on version 1.16.12
and not the latest version that is available by the development team.
This means that the latest plugins are not working at all or need some
modifications to work.
To make it easier for you, I gathered some of the plugins that are working
well, and I included them at the `addons/plugins`. For you to install the
ones you would like to use, you have to copy the `.lua` files into the
folder `.config/lite-xl/plugins/` and restart the editor.
The included plugins are the following:
**autoinsert**
Automatically inserts closing brackets and quotes. Also allows selected
text to be wrapped with brackets or quotes.
**autowrap**
Automatically hardwraps lines when typing
**bigclock**
Shows the current time and date in a view with large text
**bracketmatch**
Underlines matching pair for bracket under the caret
**colorpreview**
Underlays color values (eg. `#ff00ff` or `rgb(255, 0, 255)`) with their
resultant color.
**eofnewline-xl**
Make sure the file ends with one blank line.
**ephemeral_tabs**
Preview tabs. Opening a doc will replace the contents of the preview tab.
Marks tabs as non-preview on any change or tab double clicking.
**ghmarkdown**
Opens a preview of the current markdown file in a browser window
**indentguide**
Adds indent guides
**language_make**
Syntax for the Make build system language
**language_sh**
Syntax for shell scripting language
**lfautoinsert**
Automatically inserts indentation and closing bracket/text after newline
**markers**
Add markers to docs and jump between them quickly
**navigate**
Allows moving back and forward between document positions, reducing the
amount of scrolling
**rainbowparen**
Show nesting of parentheses with rainbow colours
**restoretabs**
Keep a list of recently closed tabs, and restore the tab in order on
cntrl+shift+t.
**selectionhighlight**
Highlights regions of code that match the current selection
## Tips and tricks
### Transitions
If you want to disable the transitions and make the scrolling a little faster,
open your configuration by clicking at the cog icon at the toolbar
(bottom left sixth icon) and add the followline at the end of the file and
save it.
```
config.transitions = false
```
### Hide files from the file list
If you would like to hide files or whole folder from the left side bar list,
open your configuration by clicking at the cog icon at the toolbar
(bottom left sixth icon) and add the followline at the end of the file and
save it. This hides all the files that start with a dot, and all the `.info`
files.
```
config.ignore_files = {"^%.", "%.info$"}
```
You can add as many rules as you want in there, to hide fore files or
folders, as you like.
## Know issues
You can find the known issues at
https://git.walkero.gr/walkero/lite-xl/issues
# Changelog
## [2.1r1] - 2022-03-27
### Changed
- Synced with master-v2.1 tag of lite-xl official github page
- Applied all the necessary changes to make it run under AmigaOS 4.1 FE
## [2.0.5r1] - 2022-03-27
### Changed
- Synced with v2.0.5 tag of lite-xl official github page
- Applied all the necessary changes to make it run under AmigaOS 4.1 FE
## [2.0.3.1] - 2022-01-18
### Changed
- Applied all the necessary changes to make it run under AmigaOS 4.1 FE

BIN
README_OS4.md.info Normal file

Binary file not shown.

View File

@ -1,5 +1,73 @@
This files document the changes done in Lite XL for each release.
### 2.1
Upgraded Lua to 5.4, which should improve performance, and provide useful extra functionality.
It should also be more available out of the box with most modern linux/unix-based package
managers.
Removed `dmon`, and implemented independent backends for dirmonitoring. Also more cleanly
split out dirmonitoring into its own class in lua, from core.init. We should now support
FreeBSD; and any other system that uses `kqueue` as their dirmonitoring library. We also
have a dummy-backend, which reverts transparnetly to scanning if there is some issue with
applying OS-level watches (such as system limits).
Removed `libagg` and the font renderer; compacted all font rendering into a single renderer.c
file which uses `libfreetype` directly. Now allows for ad-hoc bolding, italics, and underlining
of fonts.
Removed `reproc` and replaced this with a simple POSIX/Windows implementation in `process.c`.
This allows for greater tweakability (i.e. we can now `break` for debugging purposes),
performance (startup time of subprocesses is noticeably shorter), and simplicity
(we no longer have to link reproc, or winsock, on windows).
Split out `Node` and `EmptyView` into their own lua files, for plugin extensibility reasons.
Revamped StatusView API, so that plugins can more easily coexist with each other.
Removed `cp_replace`, and replaced this with a core plugin, `drawwhitespace.lua`.
Made distinction between line and block comments, and added all appropriate functionality
to the commenting/uncommenting lines.
Added in line paste mode, if you copy without a selection.
May improvements to treeview, including keyboard navigation of treeview, and ability to
specify single vs. double-click behavior.
Added in soft line wrapping as core plugin, under `linewrapping.lua`, with an
F10 to activate.
Bumped plugin mod-version number, as the rendering interface for docviews has changed.
Added in meson wraps for freetype, pcre2, and SDL2 which target public, rather than
lite-xl maintained repos.
Added in the ability to set up font fallback groups in the font renderer, if a token
doesn't have a corresponding glyph.
Added in a native plugin interface that allows for C-level interfacing with a
statically-linked lite-xl. The implementation of this may change in future.
Improved fuzzy_matching to probably give you something closer to what you're
looking for.
Improved handling of alternate keyboard layouts.
Improved ability for plugins to be loaded at a given time, by making the convention
of defining a config for the plugin use `common.merge` to merge existing hashes
together, rather than overwriting.
Added in the ability to specify mouseclicks in the keymap, allowing for easy binds of
`ctrl+lclick`, and the like.
Changed interface for keyhandling; now, all components should return true if they've
handled the event.
Added in a default keymap for `core:restart`, `ctrl+shift+r`.
Many, many, many more changes that are too numerous to list.
### 2.0.5
Revamp the project's user module so that modifications are immediately applied.

View File

@ -549,29 +549,29 @@ local commands = {
local translations = {
["previous-char"] = translate.previous_char,
["next-char"] = translate.next_char,
["previous-word-start"] = translate.previous_word_start,
["next-word-end"] = translate.next_word_end,
["previous-block-start"] = translate.previous_block_start,
["next-block-end"] = translate.next_block_end,
["start-of-doc"] = translate.start_of_doc,
["end-of-doc"] = translate.end_of_doc,
["start-of-line"] = translate.start_of_line,
["end-of-line"] = translate.end_of_line,
["start-of-word"] = translate.start_of_word,
["start-of-indentation"] = translate.start_of_indentation,
["end-of-word"] = translate.end_of_word,
["previous-line"] = DocView.translate.previous_line,
["next-line"] = DocView.translate.next_line,
["previous-page"] = DocView.translate.previous_page,
["next-page"] = DocView.translate.next_page,
["previous-char"] = translate,
["next-char"] = translate,
["previous-word-start"] = translate,
["next-word-end"] = translate,
["previous-block-start"] = translate,
["next-block-end"] = translate,
["start-of-doc"] = translate,
["end-of-doc"] = translate,
["start-of-line"] = translate,
["end-of-line"] = translate,
["start-of-word"] = translate,
["start-of-indentation"] = translate,
["end-of-word"] = translate,
["previous-line"] = DocView.translate,
["next-line"] = DocView.translate,
["previous-page"] = DocView.translate,
["next-page"] = DocView.translate,
}
for name, fn in pairs(translations) do
commands["doc:move-to-" .. name] = function() doc():move_to(fn, dv()) end
commands["doc:select-to-" .. name] = function() doc():select_to(fn, dv()) end
commands["doc:delete-to-" .. name] = function() doc():delete_to(fn, dv()) end
for name, obj in pairs(translations) do
commands["doc:move-to-" .. name] = function() doc():move_to(obj[name:gsub("-", "_")], dv()) end
commands["doc:select-to-" .. name] = function() doc():select_to(obj[name:gsub("-", "_")], dv()) end
commands["doc:delete-to-" .. name] = function() doc():delete_to(obj[name:gsub("-", "_")], dv()) end
end
commands["doc:move-to-previous-char"] = function()

View File

@ -56,8 +56,8 @@ function CommandView:get_name()
end
function CommandView:get_line_screen_position()
local x = CommandView.super.get_line_screen_position(self, 1)
function CommandView:get_line_screen_position(line, col)
local x = CommandView.super.get_line_screen_position(self, 1, col)
local _, y = self:get_content_offset()
local lh = self:get_line_height()
return x, y + (self.size.y - lh) / 2
@ -243,6 +243,7 @@ function CommandView:draw_line_gutter(idx, x, y)
x = x + style.padding.x
renderer.draw_text(self:get_font(), self.label, x, y + yoffset, color)
core.pop_clip_rect()
return self:get_line_height()
end

View File

@ -13,7 +13,8 @@ function dirwatch.new()
scanned = {},
watched = {},
reverse_watched = {},
monitor = dirmonitor.new(),
-- monitor = dirmonitor.new(),
monitor = 0,
windows_watch_top = nil,
windows_watch_count = 0
}
@ -36,23 +37,25 @@ function dirwatch:watch(directory, bool)
if not self.watched[directory] and not self.scanned[directory] then
if PLATFORM == "Windows" then
if not self.windows_watch_top or directory:find(self.windows_watch_top, 1, true) ~= 1 then
-- Get the highest level of directory that is common to this directory, and the original.
local target = directory
while self.windows_watch_top and self.windows_watch_top:find(target, 1, true) ~= 1 do
target = common.dirname(target)
end
if target ~= self.windows_watch_top then
local value = self.monitor:watch(target)
if value and value < 0 then
return self:scan(directory)
end
self.windows_watch_top = target
self.windows_watch_count = self.windows_watch_count + 1
end
-- Get the highest level of directory that is common to this directory, and the original.
local target = directory
while self.windows_watch_top and self.windows_watch_top:find(target, 1, true) ~= 1 do
target = common.dirname(target)
end
if target ~= self.windows_watch_top then
local value = self.monitor:watch(target)
if value and value < 0 then
return self:scan(directory)
end
self.windows_watch_top = target
self.windows_watch_count = self.windows_watch_count + 1
end
end
self.watched[directory] = true
else
local value = self.monitor:watch(directory)
-- TODO: Fix value to get it from monitor
-- local value = self.monitor:watch(directory)
local value = -1
-- If for whatever reason, we can't watch this directory, revert back to scanning.
-- Don't bother trying to find out why, for now.
if value and value < 0 then
@ -218,3 +221,4 @@ end
return dirwatch

View File

@ -121,14 +121,18 @@ function DocView:get_gutter_width()
end
function DocView:get_line_screen_position(idx)
function DocView:get_line_screen_position(line, col)
local x, y = self:get_content_offset()
local lh = self:get_line_height()
local gw = self:get_gutter_width()
return x + gw, y + (idx-1) * lh + style.padding.y
y = y + (line-1) * lh + style.padding.y
if col then
return x + gw + self:get_col_x_offset(line, col), y
else
return x + gw, y
end
end
function DocView:get_line_text_y_offset()
local lh = self:get_line_height()
local th = self:get_font():get_height()
@ -198,8 +202,9 @@ end
function DocView:scroll_to_line(line, ignore_if_visible, instant)
local min, max = self:get_visible_line_range()
if not (ignore_if_visible and line > min and line < max) then
local lh = self:get_line_height()
self.scroll.to.y = math.max(0, lh * (line - 1) - self.size.y / 2)
local x, y = self:get_line_screen_position(line)
local ox, oy = self:get_content_offset()
self.scroll.to.y = math.max(0, y - oy - self.size.y / 2)
if instant then
self.scroll.y = self.scroll.to.y
end
@ -208,10 +213,10 @@ end
function DocView:scroll_to_make_visible(line, col)
local min = self:get_line_height() * (line - 1)
local max = self:get_line_height() * (line + 2) - self.size.y
self.scroll.to.y = math.min(self.scroll.to.y, min)
self.scroll.to.y = math.max(self.scroll.to.y, max)
local ox, oy = self:get_content_offset()
local _, ly = self:get_line_screen_position(line, col)
local lh = self:get_line_height()
self.scroll.to.y = common.clamp(self.scroll.to.y, ly - oy - self.size.y + lh * 2, ly - oy - lh)
local gw = self:get_gutter_width()
local xoffset = self:get_col_x_offset(line, col)
local xmargin = 3 * self:get_font():get_width(' ')
@ -314,14 +319,15 @@ function DocView:draw_line_highlight(x, y)
end
function DocView:draw_line_text(idx, x, y)
function DocView:draw_line_text(line, x, y)
local default_font = self:get_font()
local tx, ty = x, y + self:get_line_text_y_offset()
for _, type, text in self.doc.highlighter:each_token(idx) do
for _, type, text in self.doc.highlighter:each_token(line) do
local color = style.syntax[type]
local font = style.syntax_fonts[type] or default_font
tx = renderer.draw_text(font, text, tx, ty, color)
end
return self:get_line_height()
end
function DocView:draw_caret(x, y)
@ -329,13 +335,13 @@ function DocView:draw_caret(x, y)
renderer.draw_rect(x, y, style.caret_width, lh, style.caret)
end
function DocView:draw_line_body(idx, x, y)
function DocView:draw_line_body(line, x, y)
-- draw highlight if any selection ends on this line
local draw_highlight = false
local hcl = config.highlight_current_line
if hcl ~= false then
for lidx, line1, col1, line2, col2 in self.doc:get_selections(false) do
if line1 == idx then
if line1 == line then
if hcl == "no_selection" then
if (line1 ~= line2) or (col1 ~= col2) then
draw_highlight = false
@ -352,14 +358,14 @@ function DocView:draw_line_body(idx, x, y)
end
-- draw selection if it overlaps this line
local lh = self:get_line_height()
for lidx, line1, col1, line2, col2 in self.doc:get_selections(true) do
if idx >= line1 and idx <= line2 then
local text = self.doc.lines[idx]
if line1 ~= idx then col1 = 1 end
if line2 ~= idx then col2 = #text + 1 end
local x1 = x + self:get_col_x_offset(idx, col1)
local x2 = x + self:get_col_x_offset(idx, col2)
local lh = self:get_line_height()
if line >= line1 and line <= line2 then
local text = self.doc.lines[line]
if line1 ~= line then col1 = 1 end
if line2 ~= line then col2 = #text + 1 end
local x1 = x + self:get_col_x_offset(line, col1)
local x2 = x + self:get_col_x_offset(line, col2)
if x1 ~= x2 then
renderer.draw_rect(x1, y, x2 - x1, lh, style.selection)
end
@ -367,20 +373,22 @@ function DocView:draw_line_body(idx, x, y)
end
-- draw line's text
self:draw_line_text(idx, x, y)
return self:draw_line_text(line, x, y)
end
function DocView:draw_line_gutter(idx, x, y, width)
function DocView:draw_line_gutter(line, x, y, width)
local color = style.line_number
for _, line1, _, line2 in self.doc:get_selections(true) do
if idx >= line1 and idx <= line2 then
if line >= line1 and line <= line2 then
color = style.line_number2
break
end
end
x = x + style.padding.x
common.draw_text(self:get_font(), color, idx, "right", x, y, width, self:get_line_height())
local lh = self:get_line_height()
common.draw_text(self:get_font(), color, line, "right", x, y, width, lh)
return lh
end
@ -394,8 +402,7 @@ function DocView:draw_overlay()
and system.window_has_focus() then
if config.disable_blink
or (core.blink_timer - core.blink_start) % T < T / 2 then
local x, y = self:get_line_screen_position(line)
self:draw_caret(x + self:get_col_x_offset(line, col), y)
self:draw_caret(self:get_line_screen_position(line, col))
end
end
end
@ -413,8 +420,7 @@ function DocView:draw()
local x, y = self:get_line_screen_position(minline)
local gw, gpad = self:get_gutter_width()
for i = minline, maxline do
self:draw_line_gutter(i, self.position.x, y, gpad and gw - gpad or gw)
y = y + lh
y = y + (self:draw_line_gutter(i, self.position.x, y, gpad and gw - gpad or gw) or lh)
end
local pos = self.position
@ -423,8 +429,7 @@ function DocView:draw()
-- right side it is redundant with the Node's clip.
core.push_clip_rect(pos.x + gw, pos.y, self.size.x - gw, self.size.y)
for i = minline, maxline do
self:draw_line_body(i, x, y)
y = y + lh
y = y + (self:draw_line_body(i, x, y) or lh)
end
self:draw_overlay()
core.pop_clip_rect()

View File

@ -727,7 +727,7 @@ function core.init()
local plugins_success, plugins_refuse_list = core.load_plugins()
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)
end
@ -1321,3 +1321,4 @@ end
return core

View File

@ -7,9 +7,10 @@ keymap.map = {}
keymap.reverse_map = {}
local macos = PLATFORM == "Mac OS X"
local os4 = PLATFORM == "AmigaOS 4"
-- 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 modkeys = modkeys_os.keys

15
data/core/modkeys-os4.lua Normal 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

View File

@ -1,6 +1,6 @@
-- this file is used by lite-xl to setup the Lua environment when starting
VERSION = "@PROJECT_VERSION@"
MOD_VERSION = "2"
VERSION = "2.1beta"
MOD_VERSION = "3"
SCALE = tonumber(os.getenv("LITE_SCALE") or os.getenv("GDK_SCALE") or os.getenv("QT_SCALE_FACTOR")) or SCALE
PATHSEP = package.config:sub(1, 1)

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local core = require "core"
local common = require "core.common"
local config = require "core.config"

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local core = require "core"
local config = require "core.config"
local Doc = require "core.doc"

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local core = require "core"
local command = require "core.command"
local keymap = require "core.keymap"

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local core = require "core"
local command = require "core.command"
local common = require "core.common"

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local style = require "core.style"
local DocView = require "core.docview"

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local syntax = require "core.syntax"
syntax.add {

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local syntax = require "core.syntax"
syntax.add {

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local syntax = require "core.syntax"
syntax.add {

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local syntax = require "core.syntax"
syntax.add {

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local syntax = require "core.syntax"
syntax.add {

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local syntax = require "core.syntax"
syntax.add {

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local syntax = require "core.syntax"
local style = require "core.style"
local core = require "core"

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local syntax = require "core.syntax"
syntax.add {

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local syntax = require "core.syntax"
syntax.add {

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local config = require "core.config"
local style = require "core.style"
local DocView = require "core.docview"

View File

@ -0,0 +1,523 @@
-- mod-version:3 -- lite-xl 2.1
local core = require "core"
local common = require "core.common"
local DocView = require "core.docview"
local Doc = require "core.doc"
local style = require "core.style"
local config = require "core.config"
local command = require "core.command"
local keymap = require "core.keymap"
local translate = require "core.doc.translate"
config.plugins.linewrapping = {
-- The type of wrapping to perform. Can be "letter" or "word".
mode = "letter",
-- If nil, uses the DocView's size, otherwise, uses this exact width.
width_override = nil,
-- Whether or not to draw a guide
guide = true,
-- Whether or not we should indent ourselves like the first line of a wrapped block.
indent = true,
-- Whether or not to enable wrapping by default when opening files.
enable_by_default = true
}
local LineWrapping = {}
-- Computes the breaks for a given line, width and mode. Returns a list of columns
-- at which the line should be broken.
function LineWrapping.compute_line_breaks(doc, default_font, line, width, mode)
local xoffset, last_i, i, last_space, last_width, begin_width = 0, 1, 1, 1, 0, 0
local splits = { 1 }
for idx, type, text in doc.highlighter:each_token(line) do
local font = style.syntax_fonts[type] or default_font
if idx == 1 and config.plugins.linewrapping.indent then
local _, indent_end = text:find("^%s+")
if indent_end then begin_width = font:get_width(text:sub(1, indent_end)) end
end
local w = font:get_width(text)
if xoffset + w > width then
for char in common.utf8_chars(text) do
w = font:get_width(char)
xoffset = xoffset + w
if xoffset > width then
if mode == "word" then
table.insert(splits, last_space + 1)
xoffset = xoffset - last_width + w + begin_width
else
table.insert(splits, i)
xoffset = w + begin_width
end
elseif char == ' ' then
last_space = i
last_width = xoffset
end
i = i + #char
end
else
xoffset = xoffset + w
i = i + #text
end
end
return splits, begin_width
end
-- breaks are held in a single table that contains n*2 elements, where n is the amount of line breaks.
-- each element represents line and column of the break. line_offset will check from the specified line
-- if the first line has not changed breaks, it will stop there.
function LineWrapping.reconstruct_breaks(docview, default_font, width, line_offset)
if width ~= math.huge then
local doc = docview.doc
-- two elements per wrapped line; first maps to original line number, second to column number.
docview.wrapped_lines = { }
-- one element per actual line; maps to the first index of in wrapped_lines for this line
docview.wrapped_line_to_idx = { }
-- one element per actual line; gives the indent width for the acutal line
docview.wrapped_line_offsets = { }
docview.wrapped_settings = { ["width"] = width, ["font"] = default_font }
for i = line_offset or 1, #doc.lines do
local breaks, offset = LineWrapping.compute_line_breaks(doc, default_font, i, width, config.plugins.linewrapping.mode)
table.insert(docview.wrapped_line_offsets, offset)
for k, col in ipairs(breaks) do
table.insert(docview.wrapped_lines, i)
table.insert(docview.wrapped_lines, col)
end
end
-- list of indices for wrapped_lines, that are based on original line number
-- holds the index to the first in the wrapped_lines list.
local last_wrap = nil
for i = 1, #docview.wrapped_lines, 2 do
if not last_wrap or last_wrap ~= docview.wrapped_lines[i] then
table.insert(docview.wrapped_line_to_idx, (i + 1) / 2)
last_wrap = docview.wrapped_lines[i]
end
end
else
docview.wrapped_lines = nil
docview.wrapped_line_to_idx = nil
docview.wrapped_line_offsets = nil
docview.wrapped_settings = nil
end
end
-- When we have an insertion or deletion, we have four sections of text.
-- 1. The unaffected section, located prior to the cursor. This is completely ignored.
-- 2. The beginning of the affected line prior to the insertion or deletion. Begins on column 1 of the selection.
-- 3. The removed/pasted lines.
-- 4. Every line after the modification, begins one line after the selection in the initial document.
function LineWrapping.update_breaks(docview, old_line1, old_line2, net_lines)
-- Step 1: Determine the index for the line for #2.
local old_idx1 = docview.wrapped_line_to_idx[old_line1] or 1
-- Step 2: Determine the index of the line for #4.
local old_idx2 = (docview.wrapped_line_to_idx[old_line2 + 1] or ((#docview.wrapped_lines / 2) + 1)) - 1
-- Step 3: Remove all old breaks for the old lines from the table, and all old widths from wrapped_line_offsets.
local offset = (old_idx1 - 1) * 2 + 1
for i = old_idx1, old_idx2 do
table.remove(docview.wrapped_lines, offset)
table.remove(docview.wrapped_lines, offset)
end
for i = old_line1, old_line2 do
table.remove(docview.wrapped_line_offsets, old_line1)
end
-- Step 4: Shift the line number of wrapped_lines past #4 by the amount of inserted/deleted lines.
if net_lines ~= 0 then
for i = offset, #docview.wrapped_lines, 2 do
docview.wrapped_lines[i] = docview.wrapped_lines[i] + net_lines
end
end
-- Step 5: Compute the breaks and offsets for the lines for #2 and #3. Insert them into the table.
local new_line1 = old_line1
local new_line2 = old_line2 + net_lines
for line = new_line1, new_line2 do
local breaks, begin_width = LineWrapping.compute_line_breaks(docview.doc, docview.wrapped_settings.font, line, docview.wrapped_settings.width, config.plugins.linewrapping.mode)
table.insert(docview.wrapped_line_offsets, line, begin_width)
for i,b in ipairs(breaks) do
table.insert(docview.wrapped_lines, offset, b)
table.insert(docview.wrapped_lines, offset, line)
offset = offset + 2
end
end
-- Step 6: Recompute the wrapped_line_to_idx cache from #2.
local line = old_line1
offset = (old_idx1 - 1) * 2 + 1
while offset < #docview.wrapped_lines do
if docview.wrapped_lines[offset + 1] == 1 then
docview.wrapped_line_to_idx[line] = ((offset - 1) / 2) + 1
line = line + 1
end
offset = offset + 2
end
while line <= #docview.wrapped_line_to_idx do
table.remove(docview.wrapped_line_to_idx)
end
end
-- Draws a guide if applicable to show where wrapping is occurring.
function LineWrapping.draw_guide(docview)
if config.plugins.linewrapping.guide and docview.wrapped_settings.width ~= math.huge then
local x, y = docview:get_content_offset()
local gw = docview:get_gutter_width()
renderer.draw_rect(x + gw + docview.wrapped_settings.width, y, 1, core.root_view.size.y, style.selection)
end
end
function LineWrapping.update_docview_breaks(docview)
local x,y,w,h = docview:get_scrollbar_rect()
local width = config.plugins.linewrapping.width_override or (docview.size.x - docview:get_gutter_width() - w)
if (not docview.wrapped_settings or docview.wrapped_settings.width == nil or width ~= docview.wrapped_settings.width) then
docview.scroll.to.x = 0
LineWrapping.reconstruct_breaks(docview, docview:get_font(), width)
end
end
local function get_idx_line_col(docview, idx)
local doc = docview.doc
if not docview.wrapped_settings then
if idx > #doc.lines then return #doc.lines, #doc.lines[#doc.lines] + 1 end
return idx, 1
end
if idx < 1 then return 1, 1 end
local offset = (idx - 1) * 2 + 1
if offset > #docview.wrapped_lines then return #doc.lines, #doc.lines[#doc.lines] + 1 end
return docview.wrapped_lines[offset], docview.wrapped_lines[offset + 1]
end
local function get_idx_line_length(docview, idx)
local doc = docview.doc
if not docview.wrapped_settings then
if idx > #doc.lines then return #doc.lines[#doc.lines] + 1 end
return #doc.lines[idx]
end
local offset = (idx - 1) * 2 + 1
local start = docview.wrapped_lines[offset + 1]
if docview.wrapped_lines[offset + 2] and docview.wrapped_lines[offset + 2] == docview.wrapped_lines[offset] then
return docview.wrapped_lines[offset + 3] - docview.wrapped_lines[offset + 1]
else
return #doc.lines[docview.wrapped_lines[offset]] - docview.wrapped_lines[offset + 1] + 1
end
end
local function get_total_wrapped_lines(docview)
if not docview.wrapped_settings then return docview.doc and #docview.doc.lines end
return #docview.wrapped_lines / 2
end
-- If line end, gives the end of an index line, rather than the first character of the next line.
local function get_line_idx_col_count(docview, line, col, line_end, ndoc)
local doc = docview.doc
if not docview.wrapped_settings then return common.clamp(line, 1, #doc.lines), col, 1, 1 end
if line > #doc.lines then return get_line_idx_col_count(docview, #doc.lines, #doc.lines[#doc.lines] + 1) end
line = math.max(line, 1)
local idx = docview.wrapped_line_to_idx[line] or 1
local ncol, scol = 1, 1
if col then
local i = idx + 1
while line == docview.wrapped_lines[(i - 1) * 2 + 1] and col >= docview.wrapped_lines[(i - 1) * 2 + 2] do
local nscol = docview.wrapped_lines[(i - 1) * 2 + 2]
if line_end and col == nscol then
break
end
scol = nscol
i = i + 1
idx = idx + 1
end
ncol = (col - scol) + 1
end
local count = (docview.wrapped_line_to_idx[line + 1] or (get_total_wrapped_lines(docview) + 1)) - (docview.wrapped_line_to_idx[line] or get_total_wrapped_lines(docview))
return idx, ncol, count, scol
end
local function get_line_col_from_index_and_x(docview, idx, x)
local doc = docview.doc
local line, col = get_idx_line_col(docview, idx)
if idx < 1 then return 1, 1 end
local xoffset, last_i, i = (col ~= 1 and docview.wrapped_line_offsets[line] or 0), col, 1
if x < xoffset then return line, col end
local default_font = docview:get_font()
for _, type, text in docview.doc.highlighter:each_token(line) do
local font, w = style.syntax_fonts[type] or default_font, 0
for char in common.utf8_chars(text) do
if i >= col then
if xoffset >= x then
return line, (xoffset - x > (w / 2) and last_i or i)
end
w = font:get_width(char)
xoffset = xoffset + w
end
last_i = i
i = i + #char
end
end
return line, #doc.lines[line]
end
local open_files = {}
local old_doc_insert = Doc.raw_insert
function Doc:raw_insert(line, col, text, undo_stack, time)
local old_lines = #self.lines
old_doc_insert(self, line, col, text, undo_stack, time)
if open_files[self] then
for i,docview in ipairs(open_files[self]) do
if docview.wrapped_settings then
local lines = #self.lines - old_lines
LineWrapping.update_breaks(docview, line, line, lines)
end
end
end
end
local old_doc_remove = Doc.raw_remove
function Doc:raw_remove(line1, col1, line2, col2, undo_stack, time)
local old_lines = #self.lines
old_doc_remove(self, line1, col1, line2, col2, undo_stack, time)
if open_files[self] then
for i,docview in ipairs(open_files[self]) do
if docview.wrapped_settings then
local lines = #self.lines - old_lines
LineWrapping.update_breaks(docview, line1, line2, lines)
end
end
end
end
local old_doc_update = DocView.update
function DocView:update()
old_doc_update(self)
if self.wrapped_settings and self.size.x > 0 then
LineWrapping.update_docview_breaks(self)
end
end
function DocView:get_scrollable_size()
if not config.scroll_past_end then
return self:get_line_height() * get_total_wrapped_lines(self) + style.padding.y * 2
end
return self:get_line_height() * (get_total_wrapped_lines(self) - 1) + self.size.y
end
local old_new = DocView.new
function DocView:new(doc)
old_new(self, doc)
if not open_files[doc] then open_files[doc] = {} end
table.insert(open_files[doc], self)
if config.plugins.linewrapping.enable_by_default then
LineWrapping.update_docview_breaks(self)
end
end
local old_scroll_to_make_visible = DocView.scroll_to_make_visible
function DocView:scroll_to_make_visible(line, col)
old_scroll_to_make_visible(self, line, col)
if self.wrapped_settings then self.scroll.to.x = 0 end
end
local old_get_visible_line_range = DocView.get_visible_line_range
function DocView:get_visible_line_range()
if not self.wrapped_settings then return old_get_visible_line_range(self) end
local x, y, x2, y2 = self:get_content_bounds()
local lh = self:get_line_height()
local minline = get_idx_line_col(self, math.max(1, math.floor(y / lh)))
local maxline = get_idx_line_col(self, math.min(get_total_wrapped_lines(self), math.floor(y2 / lh) + 1))
return minline, maxline
end
local old_get_x_offset_col = DocView.get_x_offset_col
function DocView:get_x_offset_col(line, x)
if not self.wrapped_settings then return old_get_x_offset_col(self, line, x) end
local idx = get_line_idx_col_count(self, line)
return get_line_col_from_index_and_x(self, idx, x)
end
-- If line end is true, returns the end of the previous line, in a multi-line break.
local old_get_col_x_offset = DocView.get_col_x_offset
function DocView:get_col_x_offset(line, col, line_end)
if not self.wrapped_settings then return old_get_col_x_offset(self, line, col) end
local idx, ncol, count, scol = get_line_idx_col_count(self, line, col, line_end)
local xoffset, i = (scol ~= 1 and self.wrapped_line_offsets[line] or 0), 1
local default_font = self:get_font()
for _, type, text in self.doc.highlighter:each_token(line) do
if i + #text >= scol then
if i < scol then
text = text:sub(scol - i + 1)
i = scol
end
local font = style.syntax_fonts[type] or default_font
for char in common.utf8_chars(text) do
if i >= col then
return xoffset
end
xoffset = xoffset + font:get_width(char)
i = i + #char
end
else
i = i + #text
end
end
return xoffset
end
local old_get_line_screen_position = DocView.get_line_screen_position
function DocView:get_line_screen_position(line, col)
if not self.wrapped_settings then return old_get_line_screen_position(self, line, col) end
local idx, ncol, count = get_line_idx_col_count(self, line, col)
local x, y = self:get_content_offset()
local lh = self:get_line_height()
local gw = self:get_gutter_width()
return x + gw + (col and self:get_col_x_offset(line, col) or 0), y + (idx-1) * lh + style.padding.y
end
local old_resolve_screen_position = DocView.resolve_screen_position
function DocView:resolve_screen_position(x, y)
if not self.wrapped_settings then return old_resolve_screen_position(self, x, y) end
local ox, oy = self:get_line_screen_position(1)
local idx = common.clamp(math.floor((y - oy) / self:get_line_height()) + 1, 1, get_total_wrapped_lines(self))
return get_line_col_from_index_and_x(self, idx, x - ox)
end
local old_draw_line_text = DocView.draw_line_text
function DocView:draw_line_text(line, x, y)
if not self.wrapped_settings then return old_draw_line_text(self, line, x, y) end
local default_font = self:get_font()
local tx, ty, begin_width = x, y + self:get_line_text_y_offset(), self.wrapped_line_offsets[line]
local lh = self:get_line_height()
local idx, _, count = get_line_idx_col_count(self, line)
local total_offset = 1
for _, type, text in self.doc.highlighter:each_token(line) do
local color = style.syntax[type]
local font = style.syntax_fonts[type] or default_font
local token_offset = 1
-- Split tokens if we're at the end of the document.
while text ~= nil and token_offset <= #text do
local next_line, next_line_start_col = get_idx_line_col(self, idx + 1)
if next_line ~= line then
next_line_start_col = #self.doc.lines[line]
end
local max_length = next_line_start_col - total_offset
local rendered_text = text:sub(token_offset, token_offset + max_length - 1)
tx = renderer.draw_text(font, rendered_text, tx, ty, color)
total_offset = total_offset + #rendered_text
if total_offset ~= next_line_start_col or max_length == 0 then break end
token_offset = token_offset + #rendered_text
idx = idx + 1
tx, ty = x + begin_width, ty + lh
end
end
return lh * count
end
local old_draw_line_body = DocView.draw_line_body
function DocView:draw_line_body(line, x, y)
if not self.wrapped_settings then return old_draw_line_body(self, line, x, y) end
local lh = self:get_line_height()
local idx0 = get_line_idx_col_count(self, line)
for lidx, line1, col1, line2, col2 in self.doc:get_selections(true) do
if line >= line1 and line <= line2 then
if line1 ~= line then col1 = 1 end
if line2 ~= line then col2 = #self.doc.lines[line] + 1 end
if col1 ~= col2 then
local idx1, ncol1 = get_line_idx_col_count(self, line, col1)
local idx2, ncol2 = get_line_idx_col_count(self, line, col2)
for i = idx1, idx2 do
local x1, x2 = x + (idx1 == i and self:get_col_x_offset(line1, col1) or 0)
if idx2 == i then
x2 = x + self:get_col_x_offset(line, col2)
else
x2 = x + self:get_col_x_offset(line, get_idx_line_length(self, i, line) + 1, true)
end
renderer.draw_rect(x1, y + (i - idx0) * lh, x2 - x1, lh, style.selection)
end
end
end
end
local draw_highlight = nil
for lidx, line1, col1, line2, col2 in self.doc:get_selections(true) do
-- draw line highlight if caret is on this line
if draw_highlight ~= false and config.highlight_current_line
and line1 == line and core.active_view == self then
draw_highlight = (line1 == line2 and col1 == col2)
end
end
if draw_highlight then
local _, _, count = get_line_idx_col_count(self, line)
for i=1,count do
self:draw_line_highlight(x + self.scroll.x, y + lh * (i - 1))
end
end
-- draw line's text
return self:draw_line_text(line, x, y)
end
local old_draw = DocView.draw
function DocView:draw()
old_draw(self)
if self.wrapped_settings then
LineWrapping.draw_guide(self)
end
end
local old_draw_line_gutter = DocView.draw_line_gutter
function DocView:draw_line_gutter(line, x, y, width)
local lh = self:get_line_height()
local _, _, count = get_line_idx_col_count(self, line)
return (old_draw_line_gutter(self, line, x, y, width) or lh) * count
end
local old_translate_end_of_line = translate.end_of_line
function translate.end_of_line(doc, line, col)
if not core.active_view or core.active_view.doc ~= doc or not core.active_view.wrapped_settings then old_translate_end_of_line(doc, line, col) end
local idx, ncol = get_line_idx_col_count(core.active_view, line, col)
local nline, ncol2 = get_idx_line_col(core.active_view, idx + 1)
if nline ~= line then return line, math.huge end
return line, ncol2 - 1
end
local old_translate_start_of_line = translate.start_of_line
function translate.start_of_line(doc, line, col)
if not core.active_view or core.active_view.doc ~= doc or not core.active_view.wrapped_settings then old_translate_start_of_line(doc, line, col) end
local idx, ncol = get_line_idx_col_count(core.active_view, line, col)
local nline, ncol2 = get_idx_line_col(core.active_view, idx - 1)
if nline ~= line then return line, 1 end
return line, ncol2 + 1
end
local old_previous_line = DocView.translate.previous_line
function DocView.translate.previous_line(doc, line, col, dv)
if not dv.wrapped_settings then return old_previous_line(doc, line, col, dv) end
local idx, ncol = get_line_idx_col_count(dv, line, col)
return get_line_col_from_index_and_x(dv, idx - 1, dv:get_col_x_offset(line, col))
end
local old_next_line = DocView.translate.next_line
function DocView.translate.next_line(doc, line, col, dv)
if not dv.wrapped_settings then return old_next_line(doc, line, col, dv) end
local idx, ncol = get_line_idx_col_count(dv, line, col)
return get_line_col_from_index_and_x(dv, idx + 1, dv:get_col_x_offset(line, col))
end
command.add(nil, {
["line-wrapping:enable"] = function()
if core.active_view and core.active_view.doc then
LineWrapping.update_docview_breaks(core.active_view)
end
end,
["line-wrapping:disable"] = function()
if core.active_view and core.active_view.doc then
LineWrapping.reconstruct_breaks(core.active_view, core.active_view:get_font(), math.huge)
end
end,
["line-wrapping:toggle"] = function()
if core.active_view and core.active_view.doc and core.active_view.wrapped_settings then
command.perform("line-wrapping:disable")
else
command.perform("line-wrapping:enable")
end
end
})
keymap.add {
["f10"] = "line-wrapping:toggle",
}
return LineWrapping

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local core = require "core"
local command = require "core.command"
local keymap = require "core.keymap"

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local core = require "core"
local common = require "core.common"
local keymap = require "core.keymap"

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local core = require "core"
local command = require "core.command"
local keymap = require "core.keymap"

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local core = require "core"
local config = require "core.config"
local command = require "core.command"

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local core = require "core"
local common = require "core.common"
local command = require "core.command"

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local core = require "core"
local command = require "core.command"
local translate = require "core.doc.translate"

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local core = require "core"
local common = require "core.common"
local command = require "core.command"

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local core = require "core"
local common = require "core.common"
local command = require "core.command"

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local core = require "core"
local command = require "core.command"
local Doc = require "core.doc"

View File

@ -1,4 +1,4 @@
-- mod-version:2 -- lite-xl 2.0
-- mod-version:3 -- lite-xl 2.1
local core = require "core"
local common = require "core.common"
local DocView = require "core.docview"

View File

@ -1,88 +1,88 @@
#define MyAppName "Lite XL"
#define MyAppVersion "@PROJECT_VERSION@"
#define MyAppPublisher "Lite XL Team"
#define MyAppURL "https://lite-xl.com"
#define MyAppExeName "lite-xl.exe"
#define BuildDir "@PROJECT_BUILD_DIR@"
#define SourceDir "@PROJECT_SOURCE_DIR@"
; Use /dArch option to create a setup for a different architecture, e.g.:
; iscc /dArch=x86 innosetup.iss
#ifndef Arch
#define Arch "x64"
#endif
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; To generate a new GUID, click Tools | Generate GUID inside the InnoSetup IDE.
AppId={{06761240-D97C-43DE-B9ED-C15F765A2D65}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
#if Arch=="x64"
ArchitecturesAllowed=x64
ArchitecturesInstallIn64BitMode=x64
#define ArchInternal "x86_64"
#else
#define ArchInternal "i686"
#endif
AllowNoIcons=yes
Compression=lzma
SolidCompression=yes
DefaultDirName={autopf}/{#MyAppName}
DefaultGroupName={#MyAppPublisher}
UninstallFilesDir={app}
; Uncomment the following line to run in non administrative install mode
; (install for current user only.)
;PrivilegesRequired=lowest
PrivilegesRequiredOverridesAllowed=dialog
; The [Icons] "quicklaunchicon" entry uses {userappdata}
; but its [Tasks] entry has a proper IsAdminInstallMode Check.
UsedUserAreasWarning=no
OutputDir=.
OutputBaseFilename=LiteXL-{#MyAppVersion}-{#ArchInternal}-setup
;DisableDirPage=yes
;DisableProgramGroupPage=yes
LicenseFile={#SourceDir}/LICENSE
SetupIconFile={#SourceDir}/resources/icons/icon.ico
WizardImageFile="{#SourceDir}/scripts/innosetup/wizard-modern-image.bmp"
WizardSmallImageFile="{#SourceDir}/scripts/innosetup/litexl-55px.bmp"
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 6.1; Check: not IsAdminInstallMode
Name: "portablemode"; Description: "Portable Mode"; Flags: unchecked
[Files]
Source: "{#BuildDir}/src/lite-xl.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#BuildDir}/mingwLibs{#Arch}/*"; DestDir: "{app}"; Flags: ignoreversion ; Check: DirExists(ExpandConstant('{#BuildDir}/mingwLibs{#Arch}'))
Source: "{#SourceDir}/data/*"; DestDir: "{app}/data"; Flags: ignoreversion recursesubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Check: not WizardIsTaskSelected('portablemode')
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"; Check: not WizardIsTaskSelected('portablemode')
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon; Check: not WizardIsTaskSelected('portablemode')
; Name: "{usersendto}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
[Run]
Filename: "{app}/{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
[Setup]
Uninstallable=not WizardIsTaskSelected('portablemode')
#define MyAppName "Lite XL"
#define MyAppVersion "@PROJECT_VERSION@"
#define MyAppPublisher "Lite XL Team"
#define MyAppURL "https://lite-xl.com"
#define MyAppExeName "lite-xl.exe"
#define BuildDir "@PROJECT_BUILD_DIR@"
#define SourceDir "@PROJECT_SOURCE_DIR@"
; Use /dArch option to create a setup for a different architecture, e.g.:
; iscc /dArch=x86 innosetup.iss
#ifndef Arch
#define Arch "x64"
#endif
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; To generate a new GUID, click Tools | Generate GUID inside the InnoSetup IDE.
AppId={{06761240-D97C-43DE-B9ED-C15F765A2D65}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
#if Arch=="x64"
ArchitecturesAllowed=x64
ArchitecturesInstallIn64BitMode=x64
#define ArchInternal "x86_64"
#else
#define ArchInternal "i686"
#endif
AllowNoIcons=yes
Compression=lzma
SolidCompression=yes
DefaultDirName={autopf}/{#MyAppName}
DefaultGroupName={#MyAppPublisher}
UninstallFilesDir={app}
; Uncomment the following line to run in non administrative install mode
; (install for current user only.)
;PrivilegesRequired=lowest
PrivilegesRequiredOverridesAllowed=dialog
; The [Icons] "quicklaunchicon" entry uses {userappdata}
; but its [Tasks] entry has a proper IsAdminInstallMode Check.
UsedUserAreasWarning=no
OutputDir=.
OutputBaseFilename=LiteXL-{#MyAppVersion}-{#ArchInternal}-setup
;DisableDirPage=yes
;DisableProgramGroupPage=yes
LicenseFile={#SourceDir}/LICENSE
SetupIconFile={#SourceDir}/resources/icons/icon.ico
WizardImageFile="{#SourceDir}/scripts/innosetup/wizard-modern-image.bmp"
WizardSmallImageFile="{#SourceDir}/scripts/innosetup/litexl-55px.bmp"
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 6.1; Check: not IsAdminInstallMode
Name: "portablemode"; Description: "Portable Mode"; Flags: unchecked
[Files]
Source: "{#BuildDir}/src/lite-xl.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#BuildDir}/mingwLibs{#Arch}/*"; DestDir: "{app}"; Flags: ignoreversion ; Check: DirExists(ExpandConstant('{#BuildDir}/mingwLibs{#Arch}'))
Source: "{#SourceDir}/data/*"; DestDir: "{app}/data"; Flags: ignoreversion recursesubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Check: not WizardIsTaskSelected('portablemode')
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"; Check: not WizardIsTaskSelected('portablemode')
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon; Check: not WizardIsTaskSelected('portablemode')
; Name: "{usersendto}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
[Run]
Filename: "{app}/{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
[Setup]
Uninstallable=not WizardIsTaskSelected('portablemode')

View File

@ -3,14 +3,14 @@
int luaopen_system(lua_State *L);
int luaopen_renderer(lua_State *L);
int luaopen_regex(lua_State *L);
int luaopen_process(lua_State *L);
// int luaopen_process(lua_State *L);
int luaopen_dirmonitor(lua_State* L);
static const luaL_Reg libs[] = {
{ "system", luaopen_system },
{ "renderer", luaopen_renderer },
{ "regex", luaopen_regex },
{ "process", luaopen_process },
// { "process", luaopen_process },
{ "dirmonitor", luaopen_dirmonitor },
{ NULL, NULL }
};

View File

@ -5,6 +5,8 @@
#elif __linux__
#include <sys/inotify.h>
#include <limits.h>
#elif __amigaos4__
// #define DIRMONITOR_BACKEND 'os4'
#else
#include <sys/event.h>
#endif
@ -94,3 +96,4 @@ int luaopen_dirmonitor(lua_State* L) {
lua_setfield(L, -2, "__index");
return 1;
}

23
src/api/dirmonitor/os4.c Normal file
View File

@ -0,0 +1,23 @@
#include <stdlib.h>
struct dirmonitor {
};
struct dirmonitor* init_dirmonitor_os4() {
return NULL;
}
void deinit_dirmonitor_os4(struct dirmonitor* monitor) {
}
int check_dirmonitor_os4(struct dirmonitor* monitor, int (*change_callback)(int, const char*, void*), void* data) {
return -1;
}
int add_dirmonitor_os4(struct dirmonitor* monitor, const char* path) {
return -1;
}
void remove_dirmonitor_os4(struct dirmonitor* monitor, int fd) {
}

View File

@ -7,13 +7,15 @@
#include <errno.h>
#include <sys/stat.h>
#include "api.h"
#include "../rencache.h"
#include "rencache.h"
#ifdef _WIN32
#include <direct.h>
#include <windows.h>
#include <fileapi.h>
#elif __linux__
#include <sys/vfs.h>
#elif __amigaos4__
#include "platform/amigaos4.h"
#endif
extern SDL_Window *window;
@ -320,7 +322,11 @@ static int f_set_window_mode(lua_State *L) {
int n = luaL_checkoption(L, 1, "normal", window_opts);
SDL_SetWindowFullscreen(window,
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_MINIMIZED) { SDL_MinimizeWindow(window); }
return 0;
@ -501,6 +507,9 @@ static int f_list_dir(lua_State *L) {
#include <windows.h>
#define realpath(x, y) _fullpath(y, x, MAX_PATH)
#endif
#ifdef __amigaos4__
#define realpath(x, y) _fullpath(x)
#endif
static int f_absolute_path(lua_State *L) {
const char *path = luaL_checkstring(L, 1);

View File

@ -12,6 +12,8 @@
#include <signal.h>
#elif __APPLE__
#include <mach-o/dyld.h>
#elif __amigaos4__
#include "platform/amigaos4.h"
#endif
@ -43,6 +45,8 @@ static void get_exe_filename(char *buf, int sz) {
char exepath[size];
_NSGetExecutablePath(exepath, &size);
realpath(exepath, buf);
#elif __amigaos4__
strcpy(buf, _fullpath("./lite"));
#else
strcpy(buf, "./lite");
#endif
@ -109,6 +113,7 @@ int main(int argc, char **argv) {
window = SDL_CreateWindow(
"", 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_SetWindowDisplayMode(window, &dm);
init_window_icon();
ren_init(window);
@ -150,6 +155,9 @@ init_lua:
" HOME = os.getenv('" LITE_OS_HOME "')\n"
" local exedir = EXEFILE:match('^(.*)" LITE_PATHSEP_PATTERN LITE_NONPATHSEP_PATTERN "$')\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"
" core = require(os.getenv('LITE_XL_RUNTIME') or 'core')\n"
" core.init()\n"

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 OS4 2.1beta (27.03.2022)"
#define VERSTAG "\0$VER: " VSTRING
static CONST_STRPTR stack USED = "$STACK:102400";
static CONST_STRPTR version USED = VERSTAG;
char *_fullpath(const char *);
#endif

View File

@ -36,7 +36,7 @@ typedef struct {
typedef struct {
SDL_Surface* surface;
GlyphMetric metrics[MAX_GLYPHSET];
GlyphMetric metrics[MAX_GLYPHSET];
} GlyphSet;
typedef struct RenFont {
@ -67,7 +67,7 @@ static const char* utf8_to_codepoint(const char *p, unsigned *dst) {
}
static int font_set_load_options(RenFont* font) {
int load_target = font->antialiasing == FONT_ANTIALIASING_NONE ? FT_LOAD_TARGET_MONO
int load_target = font->antialiasing == FONT_ANTIALIASING_NONE ? FT_LOAD_TARGET_MONO
: (font->hinting == FONT_HINTING_SLIGHT ? FT_LOAD_TARGET_LIGHT : FT_LOAD_TARGET_NORMAL);
int hinting = font->hinting == FONT_HINTING_NONE ? FT_LOAD_NO_HINTING : FT_LOAD_FORCE_AUTOHINT;
return load_target | hinting;
@ -144,7 +144,7 @@ static void font_load_glyphset(RenFont* font, int idx) {
FT_GlyphSlot slot = font->face->glyph;
font_set_style(&slot->outline, (64 / bitmaps_cached) * j, font->style);
if (FT_Render_Glyph(slot, render_option))
continue;
continue;
for (int line = 0; line < slot->bitmap.rows; ++line) {
int target_offset = set->surface->pitch * line + set->metrics[i].x0 * byte_width;
int source_offset = line * slot->bitmap.pitch;
@ -202,7 +202,7 @@ RenFont* ren_font_load(const char* path, float size, ERenFontAntialiasing antial
font->space_advance = font_get_glyphset(font, ' ', 0)->metrics[' '].xadvance;
font->tab_advance = font->space_advance * 2;
return font;
failure:
failure:
FT_Done_Face(face);
return NULL;
}
@ -227,7 +227,7 @@ void ren_font_free(RenFont* font) {
void ren_font_group_set_tab_size(RenFont **fonts, int n) {
for (int j = 0; j < FONT_FALLBACK_MAX && fonts[j]; ++j) {
for (int i = 0; i < (fonts[j]->antialiasing == FONT_ANTIALIASING_SUBPIXEL ? SUBPIXEL_BITMAPS_CACHED : 1); ++i)
for (int i = 0; i < (fonts[j]->antialiasing == FONT_ANTIALIASING_SUBPIXEL ? SUBPIXEL_BITMAPS_CACHED : 1); ++i)
font_get_glyphset(fonts[j], '\t', i)->metrics['\t'].xadvance = fonts[j]->space_advance * n;
}
}
@ -268,11 +268,11 @@ float ren_draw_text(RenFont **fonts, const char *text, float x, int y, RenColor
const char* end = text + strlen(text);
unsigned char* destination_pixels = surface->pixels;
int clip_end_x = clip.x + clip.width, clip_end_y = clip.y + clip.height;
while (text < end) {
unsigned int codepoint, r, g, b;
text = utf8_to_codepoint(text, &codepoint);
GlyphSet* set = NULL; GlyphMetric* metric = NULL;
GlyphSet* set = NULL; GlyphMetric* metric = NULL;
RenFont* font = font_group_get_glyph(&set, &metric, fonts, codepoint, (int)(fmod(pen_x, 1.0) * SUBPIXEL_BITMAPS_CACHED));
int start_x = floor(pen_x) + metric->bitmap_left;
int end_x = (metric->x1 - metric->x0) + start_x;
@ -344,8 +344,14 @@ void ren_draw_rect(RenRect rect, RenColor color) {
SDL_Surface *surface = renwin_get_surface(&window_renderer);
uint32_t *d = surface->pixels;
#ifdef __amigaos4__
d += x1 + y1 * surface->pitch/sizeof(uint32_t);
int dr = surface->pitch/sizeof(uint32_t) - (x2 - x1);
#else
d += x1 + y1 * surface->w;
int dr = surface->w - (x2 - x1);
#endif
if (color.a == 0xff) {
uint32_t translated = SDL_MapRGB(surface->format, color.r, color.g, color.b);
SDL_Rect rect = { x1, y1, x2 - x1, y2 - y1 };

View File

@ -9,6 +9,18 @@ static int query_surface_scale(RenWindow *ren) {
SDL_GetWindowSize(ren->window, &w_points, &h_points);
/* We consider that the ratio pixel/point will always be an integer and
it is the same along the x and the y axis. */
#ifdef __amigaos4__
// 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;
}
#endif
assert(w_pixels % w_points == 0 && h_pixels % h_points == 0 && w_pixels / w_points == h_pixels / h_points);
return w_pixels / w_points;
}
@ -20,7 +32,7 @@ static void setup_renderer(RenWindow *ren, int w, int h) {
SDL_DestroyTexture(ren->texture);
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->surface_scale = query_surface_scale(ren);
}