Compare commits
No commits in common. "amigaos4" and "v1.04" have entirely different histories.
|
@ -1,3 +0,0 @@
|
||||||
# These are supported funding model platforms
|
|
||||||
|
|
||||||
github: rxi
|
|
|
@ -1,5 +0,0 @@
|
||||||
src/*.o
|
|
||||||
src/*/*.o
|
|
||||||
src/*/*/*.o
|
|
||||||
lite
|
|
||||||
*.txt
|
|
105
Makefile
105
Makefile
|
@ -1,105 +0,0 @@
|
||||||
#
|
|
||||||
# Makefile generated by:
|
|
||||||
# codebench 0.55
|
|
||||||
#
|
|
||||||
# Project: lite
|
|
||||||
#
|
|
||||||
# Created on: 15-12-2021 22:58:23
|
|
||||||
#
|
|
||||||
#
|
|
||||||
|
|
||||||
###################################################################
|
|
||||||
##
|
|
||||||
##//// Objects
|
|
||||||
##
|
|
||||||
###################################################################
|
|
||||||
|
|
||||||
lite_OBJ := \
|
|
||||||
src/lib/stb/stb_truetype.o src/api/renderer.o src/api/renderer_font.o \
|
|
||||||
src/api/system.o src/main.o src/api/api.o \
|
|
||||||
src/rencache.o src/renderer.o
|
|
||||||
|
|
||||||
|
|
||||||
###################################################################
|
|
||||||
##
|
|
||||||
##//// Variables and Environment
|
|
||||||
##
|
|
||||||
###################################################################
|
|
||||||
|
|
||||||
CC := gcc:bin/gcc
|
|
||||||
|
|
||||||
INCPATH := -I. -Isrc
|
|
||||||
|
|
||||||
CFLAGS := $(INCPATH) -D__USE_INLINE__ -Wall -Werror -Wwrite-strings
|
|
||||||
|
|
||||||
|
|
||||||
###################################################################
|
|
||||||
##
|
|
||||||
##//// General rules
|
|
||||||
##
|
|
||||||
###################################################################
|
|
||||||
|
|
||||||
.PHONY: all all-before all-after clean clean-custom realclean
|
|
||||||
|
|
||||||
all: all-before lite all-after
|
|
||||||
|
|
||||||
all-before:
|
|
||||||
# You can add rules here to execute before the project is built
|
|
||||||
|
|
||||||
all-after:
|
|
||||||
# You can add rules here to execute after the project is built
|
|
||||||
|
|
||||||
clean: clean-custom
|
|
||||||
@echo "Cleaning compiler objects..."
|
|
||||||
@rm -f $(lite_OBJ)
|
|
||||||
|
|
||||||
realclean:
|
|
||||||
@echo "Cleaning compiler objects and targets..."
|
|
||||||
@rm -f $(lite_OBJ) lite
|
|
||||||
|
|
||||||
|
|
||||||
###################################################################
|
|
||||||
##
|
|
||||||
##//// Targets
|
|
||||||
##
|
|
||||||
###################################################################
|
|
||||||
|
|
||||||
lite: $(lite_OBJ)
|
|
||||||
@echo "Linking lite"
|
|
||||||
@gcc:bin/gcc -o lite $(lite_OBJ) -llua -lSDL2 -lpthread -lauto
|
|
||||||
@echo "Removing stale debug target: lite"
|
|
||||||
@rm -f lite.debug
|
|
||||||
|
|
||||||
|
|
||||||
###################################################################
|
|
||||||
##
|
|
||||||
##//// Standard rules
|
|
||||||
##
|
|
||||||
###################################################################
|
|
||||||
|
|
||||||
# A default rule to make all the objects listed below
|
|
||||||
# because we are hiding compiler commands from the output
|
|
||||||
|
|
||||||
.c.o:
|
|
||||||
@echo "Compiling $<"
|
|
||||||
@$(CC) -c $< -o $*.o $(CFLAGS)
|
|
||||||
|
|
||||||
src/api/api.o: src/api/api.c
|
|
||||||
|
|
||||||
src/api/renderer.o: src/api/renderer.c src/api/api.h src/renderer.h \
|
|
||||||
|
|
||||||
|
|
||||||
src/api/renderer_font.o: src/api/renderer_font.c src/api/api.h src/renderer.h \
|
|
||||||
|
|
||||||
|
|
||||||
src/api/system.o: src/api/system.c src/api/api.h
|
|
||||||
|
|
||||||
src/main.o: src/main.c src/api/api.h src/renderer.h \
|
|
||||||
|
|
||||||
|
|
||||||
src/rencache.o: src/rencache.c
|
|
||||||
|
|
||||||
src/renderer.o: src/renderer.c src/lib/stb/stb_truetype.h
|
|
||||||
|
|
||||||
src/lib/stb/stb_truetype.o: src/lib/stb/stb_truetype.c
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ A lightweight text editor written in Lua
|
||||||
|
|
||||||
* **[Get lite](https://github.com/rxi/lite/releases/latest)** — Download
|
* **[Get lite](https://github.com/rxi/lite/releases/latest)** — Download
|
||||||
for Windows and Linux
|
for Windows and Linux
|
||||||
* **[Get started](doc/usage.md)** — A quick overview on how to get started
|
|
||||||
* **[Get plugins](https://github.com/rxi/lite-plugins)** — Add additional
|
* **[Get plugins](https://github.com/rxi/lite-plugins)** — Add additional
|
||||||
functionality
|
functionality
|
||||||
* **[Get color themes](https://github.com/rxi/lite-colors)** — Add additional colors
|
* **[Get color themes](https://github.com/rxi/lite-colors)** — Add additional colors
|
||||||
|
@ -24,10 +23,9 @@ The editor can be customized by making changes to the
|
||||||
[user module](data/user/init.lua).
|
[user module](data/user/init.lua).
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
You can build the project yourself on Linux using the `build.sh` script
|
You can build the project yourself on Linux using the provided `build.sh`
|
||||||
or on Windows using the `build.bat` script *([MinGW](https://nuwen.net/mingw.html) is required)*.
|
script. Note that the project does not need to be rebuilt if you are only making
|
||||||
Note that the project does not need to be rebuilt if you are only making changes
|
changes to the Lua portion of the code.
|
||||||
to the Lua portion of the code.
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
Any additional functionality that can be added through a plugin should be done
|
Any additional functionality that can be added through a plugin should be done
|
||||||
|
|
16
build.bat
16
build.bat
|
@ -1,16 +0,0 @@
|
||||||
@echo off
|
|
||||||
|
|
||||||
rem download this:
|
|
||||||
rem https://nuwen.net/mingw.html
|
|
||||||
|
|
||||||
echo compiling (windows)...
|
|
||||||
|
|
||||||
windres res.rc -O coff -o res.res
|
|
||||||
gcc src/*.c src/api/*.c src/lib/lua52/*.c src/lib/stb/*.c^
|
|
||||||
-O3 -s -std=gnu11 -fno-strict-aliasing -Isrc -DLUA_USE_POPEN^
|
|
||||||
-Iwinlib/SDL2-2.0.10/x86_64-w64-mingw32/include^
|
|
||||||
-lmingw32 -lm -lSDL2main -lSDL2 -Lwinlib/SDL2-2.0.10/x86_64-w64-mingw32/lib^
|
|
||||||
-mwindows res.res^
|
|
||||||
-o lite.exe
|
|
||||||
|
|
||||||
echo done
|
|
5
build.sh
5
build.sh
|
@ -1,13 +1,13 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
cflags="-Wall -O3 -g -std=gnu11 -fno-strict-aliasing -Isrc"
|
cflags="-Wall -O3 -g -std=gnu11 -Isrc -DLUA_USE_POPEN"
|
||||||
lflags="-lSDL2 -lm"
|
lflags="-lSDL2 -lm"
|
||||||
|
|
||||||
if [[ $* == *windows* ]]; then
|
if [[ $* == *windows* ]]; then
|
||||||
platform="windows"
|
platform="windows"
|
||||||
outfile="lite.exe"
|
outfile="lite.exe"
|
||||||
compiler="x86_64-w64-mingw32-gcc"
|
compiler="x86_64-w64-mingw32-gcc"
|
||||||
cflags="$cflags -DLUA_USE_POPEN -Iwinlib/SDL2-2.0.10/x86_64-w64-mingw32/include"
|
cflags="$cflags -Iwinlib/SDL2-2.0.10/x86_64-w64-mingw32/include"
|
||||||
lflags="$lflags -Lwinlib/SDL2-2.0.10/x86_64-w64-mingw32/lib"
|
lflags="$lflags -Lwinlib/SDL2-2.0.10/x86_64-w64-mingw32/lib"
|
||||||
lflags="-lmingw32 -lSDL2main $lflags -mwindows -o $outfile res.res"
|
lflags="-lmingw32 -lSDL2main $lflags -mwindows -o $outfile res.res"
|
||||||
x86_64-w64-mingw32-windres res.rc -O coff -o res.res
|
x86_64-w64-mingw32-windres res.rc -O coff -o res.res
|
||||||
|
@ -15,7 +15,6 @@ else
|
||||||
platform="unix"
|
platform="unix"
|
||||||
outfile="lite"
|
outfile="lite"
|
||||||
compiler="gcc"
|
compiler="gcc"
|
||||||
cflags="$cflags -DLUA_USE_POSIX"
|
|
||||||
lflags="$lflags -o $outfile"
|
lflags="$lflags -o $outfile"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ command.add(nil, {
|
||||||
end)
|
end)
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["core:find-command"] = function()
|
["core:command-finder"] = function()
|
||||||
local commands = command.get_all_valid()
|
local commands = command.get_all_valid()
|
||||||
core.command_view:enter("Do Command", function(text, item)
|
core.command_view:enter("Do Command", function(text, item)
|
||||||
if item then
|
if item then
|
||||||
|
@ -54,15 +54,15 @@ command.add(nil, {
|
||||||
end)
|
end)
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["core:find-file"] = function()
|
["core:file-finder"] = function()
|
||||||
core.command_view:enter("Open File From Project", function(text, item)
|
core.command_view:enter("Open File From Project", function(text, item)
|
||||||
text = item and item.text or text
|
text = core.project_dir .. PATHSEP .. (item and item.text or text)
|
||||||
core.root_view:open_doc(core.open_doc(text))
|
core.root_view:open_doc(core.open_doc(text))
|
||||||
end, function(text)
|
end, function(text)
|
||||||
local files = {}
|
local files = {}
|
||||||
for _, item in pairs(core.project_files) do
|
for _, item in pairs(core.project_files) do
|
||||||
if item.type == "file" then
|
if item.type == "file" then
|
||||||
table.insert(files, item.filename)
|
table.insert(files, item.filename:sub(#core.project_dir + 2))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return common.fuzzy_match(files, text)
|
return common.fuzzy_match(files, text)
|
||||||
|
@ -89,7 +89,7 @@ command.add(nil, {
|
||||||
end,
|
end,
|
||||||
|
|
||||||
["core:open-project-module"] = function()
|
["core:open-project-module"] = function()
|
||||||
local filename = ".lite_project.lua"
|
local filename = core.project_dir .. "/.lite_project.lua"
|
||||||
if system.get_file_info(filename) then
|
if system.get_file_info(filename) then
|
||||||
core.root_view:open_doc(core.open_doc(filename))
|
core.root_view:open_doc(core.open_doc(filename))
|
||||||
else
|
else
|
||||||
|
|
|
@ -160,9 +160,7 @@ local commands = {
|
||||||
local line1, _, line2 = doc():get_selection(true)
|
local line1, _, line2 = doc():get_selection(true)
|
||||||
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 ]*", " ")
|
||||||
return x:find("^%s*$") and x or x .. " "
|
|
||||||
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 doc():has_selection() then
|
||||||
|
@ -322,10 +320,10 @@ local commands = {
|
||||||
local translations = {
|
local translations = {
|
||||||
["previous-char"] = translate.previous_char,
|
["previous-char"] = translate.previous_char,
|
||||||
["next-char"] = translate.next_char,
|
["next-char"] = translate.next_char,
|
||||||
["previous-word-start"] = translate.previous_word_start,
|
["previous-word-boundary"] = translate.previous_word_boundary,
|
||||||
["next-word-end"] = translate.next_word_end,
|
["next-word-boundary"] = translate.next_word_boundary,
|
||||||
["previous-block-start"] = translate.previous_block_start,
|
["previous-start-of-block"] = translate.previous_start_of_block,
|
||||||
["next-block-end"] = translate.next_block_end,
|
["next-start-of-block"] = translate.next_start_of_block,
|
||||||
["start-of-doc"] = translate.start_of_doc,
|
["start-of-doc"] = translate.start_of_doc,
|
||||||
["end-of-doc"] = translate.end_of_doc,
|
["end-of-doc"] = translate.end_of_doc,
|
||||||
["start-of-line"] = translate.start_of_line,
|
["start-of-line"] = translate.start_of_line,
|
||||||
|
|
|
@ -45,24 +45,23 @@ local function find(label, search_fn)
|
||||||
else
|
else
|
||||||
core.error("Couldn't find %q", text)
|
core.error("Couldn't find %q", text)
|
||||||
dv.doc:set_selection(table.unpack(sel))
|
dv.doc:set_selection(table.unpack(sel))
|
||||||
dv:scroll_to_make_visible(sel[1], sel[2])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end, function(text)
|
end, function(text)
|
||||||
local ok, line1, col1, line2, col2 = pcall(search_fn, dv.doc, sel[1], sel[2], text)
|
local ok, line1, col1, line2, col2 = pcall(search_fn, dv.doc, sel[1], sel[2], text)
|
||||||
if ok and line1 and text ~= "" then
|
if text == "" then
|
||||||
|
dv.doc:set_selection(table.unpack(sel))
|
||||||
|
elseif ok and line1 then
|
||||||
dv.doc:set_selection(line2, col2, line1, col1)
|
dv.doc:set_selection(line2, col2, line1, col1)
|
||||||
dv:scroll_to_line(line2, true)
|
dv:scroll_to_line(line2, true)
|
||||||
found = true
|
found = true
|
||||||
else
|
else
|
||||||
dv.doc:set_selection(table.unpack(sel))
|
|
||||||
found = false
|
found = false
|
||||||
end
|
end
|
||||||
|
|
||||||
end, function(explicit)
|
end, function(explicit)
|
||||||
if explicit then
|
if explicit then
|
||||||
dv.doc:set_selection(table.unpack(sel))
|
dv.doc:set_selection(table.unpack(sel))
|
||||||
dv:scroll_to_make_visible(sel[1], sel[2])
|
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
|
@ -94,7 +94,7 @@ for _, dir in ipairs { "left", "right", "up", "down" } do
|
||||||
end
|
end
|
||||||
local node = core.root_view.root_node:get_child_overlapping_point(x, y)
|
local node = core.root_view.root_node:get_child_overlapping_point(x, y)
|
||||||
if not node:get_locked_size() then
|
if not node:get_locked_size() then
|
||||||
core.set_active_view(node.active_view)
|
core.active_view = node.active_view
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -111,8 +111,9 @@ function CommandView:enter(text, submit, suggest, cancel)
|
||||||
submit = submit or noop,
|
submit = submit or noop,
|
||||||
suggest = suggest or noop,
|
suggest = suggest or noop,
|
||||||
cancel = cancel or noop,
|
cancel = cancel or noop,
|
||||||
|
view = core.active_view
|
||||||
}
|
}
|
||||||
core.set_active_view(self)
|
core.active_view = self
|
||||||
self:update_suggestions()
|
self:update_suggestions()
|
||||||
self.gutter_text_brightness = 100
|
self.gutter_text_brightness = 100
|
||||||
self.label = text .. ": "
|
self.label = text .. ": "
|
||||||
|
@ -121,7 +122,7 @@ end
|
||||||
|
|
||||||
function CommandView:exit(submitted, inexplicit)
|
function CommandView:exit(submitted, inexplicit)
|
||||||
if core.active_view == self then
|
if core.active_view == self then
|
||||||
core.set_active_view(core.last_active_view)
|
core.active_view = self.state.view
|
||||||
end
|
end
|
||||||
local cancel = self.state.cancel
|
local cancel = self.state.cancel
|
||||||
self.state = default_state
|
self.state = default_state
|
||||||
|
|
|
@ -46,7 +46,7 @@ end
|
||||||
|
|
||||||
|
|
||||||
function Highlighter:invalidate(idx)
|
function Highlighter:invalidate(idx)
|
||||||
self.first_invalid_line = math.min(self.first_invalid_line, idx)
|
self.first_invalid_line = idx
|
||||||
self.max_wanted_line = math.min(self.max_wanted_line, #self.doc.lines)
|
self.max_wanted_line = math.min(self.max_wanted_line, #self.doc.lines)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -56,8 +56,7 @@ end
|
||||||
|
|
||||||
|
|
||||||
function Doc:reset_syntax()
|
function Doc:reset_syntax()
|
||||||
local header = self:get_text(1, 1, self:position_offset(1, 1, 128))
|
local syn = syntax.get(self.filename or "")
|
||||||
local syn = syntax.get(self.filename or "", header)
|
|
||||||
if self.syntax ~= syn then
|
if self.syntax ~= syn then
|
||||||
self.syntax = syn
|
self.syntax = syn
|
||||||
self.highlighter:reset()
|
self.highlighter:reset()
|
||||||
|
|
|
@ -28,32 +28,33 @@ function translate.next_char(doc, line, col)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function translate.previous_word_start(doc, line, col)
|
function translate.previous_word_boundary(doc, line, col)
|
||||||
local prev
|
local char = doc:get_char(doc:position_offset(line, col, -1))
|
||||||
while line > 1 or col > 1 do
|
local inword = not is_non_word(char)
|
||||||
local l, c = doc:position_offset(line, col, -1)
|
repeat
|
||||||
local char = doc:get_char(l, c)
|
local line2, col2 = line, col
|
||||||
if prev and prev ~= char or not is_non_word(char) then
|
line, col = doc:position_offset(line, col, -1)
|
||||||
|
if line == line2 and col == col2 then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
prev, line, col = char, l, c
|
local c = doc:get_char(doc:position_offset(line, col, -1))
|
||||||
end
|
until inword and is_non_word(c) or not inword and c ~= char
|
||||||
return translate.start_of_word(doc, line, col)
|
return line, col
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function translate.next_word_end(doc, line, col)
|
function translate.next_word_boundary(doc, line, col)
|
||||||
local prev
|
local char = doc:get_char(line, col)
|
||||||
local end_line, end_col = translate.end_of_doc(doc, line, col)
|
local inword = not is_non_word(char)
|
||||||
while line < end_line or col < end_col do
|
repeat
|
||||||
local char = doc:get_char(line, col)
|
local line2, col2 = line, col
|
||||||
if prev and prev ~= char or not is_non_word(char) then
|
line, col = doc:position_offset(line, col, 1)
|
||||||
|
if line == line2 and col == col2 then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
line, col = doc:position_offset(line, col, 1)
|
local c = doc:get_char(line, col)
|
||||||
prev = char
|
until inword and is_non_word(c) or not inword and c ~= char
|
||||||
end
|
return line, col
|
||||||
return translate.end_of_word(doc, line, col)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,30 +86,30 @@ function translate.end_of_word(doc, line, col)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function translate.previous_block_start(doc, line, col)
|
function translate.previous_start_of_block(doc, line, col)
|
||||||
while true do
|
while true do
|
||||||
line = line - 1
|
line = line - 1
|
||||||
if line <= 1 then
|
if line <= 1 then
|
||||||
return 1, 1
|
return 1, 1
|
||||||
end
|
end
|
||||||
if doc.lines[line-1]:find("^%s*$")
|
if doc.lines[line-1]:match("^%s*$")
|
||||||
and not doc.lines[line]:find("^%s*$") then
|
and not doc.lines[line]:match("^%s*$") then
|
||||||
return line, (doc.lines[line]:find("%S"))
|
return line, (doc.lines[line]:find("%S"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function translate.next_block_end(doc, line, col)
|
function translate.next_start_of_block(doc, line, col)
|
||||||
while true do
|
while true do
|
||||||
|
line = line + 1
|
||||||
if line >= #doc.lines then
|
if line >= #doc.lines then
|
||||||
return #doc.lines, 1
|
return #doc.lines, 1
|
||||||
end
|
end
|
||||||
if doc.lines[line+1]:find("^%s*$")
|
if doc.lines[line-1]:match("^%s*$")
|
||||||
and not doc.lines[line]:find("^%s*$") then
|
and not doc.lines[line]:match("^%s*$") then
|
||||||
return line+1, #doc.lines[line+1]
|
return line, (doc.lines[line]:find("%S"))
|
||||||
end
|
end
|
||||||
line = line + 1
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -192,42 +192,28 @@ function DocView:scroll_to_make_visible(line, col)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function mouse_selection(doc, clicks, line1, col1, line2, col2)
|
|
||||||
local swap = line2 < line1 or line2 == line1 and col2 <= col1
|
|
||||||
if swap then
|
|
||||||
line1, col1, line2, col2 = line2, col2, line1, col1
|
|
||||||
end
|
|
||||||
if clicks == 2 then
|
|
||||||
line1, col1 = translate.start_of_word(doc, line1, col1)
|
|
||||||
line2, col2 = translate.end_of_word(doc, line2, col2)
|
|
||||||
elseif clicks == 3 then
|
|
||||||
if line2 == #doc.lines and doc.lines[#doc.lines] ~= "\n" then
|
|
||||||
doc:insert(math.huge, math.huge, "\n")
|
|
||||||
end
|
|
||||||
line1, col1, line2, col2 = line1, 1, line2 + 1, 1
|
|
||||||
end
|
|
||||||
if swap then
|
|
||||||
return line2, col2, line1, col1
|
|
||||||
end
|
|
||||||
return line1, col1, line2, col2
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function DocView:on_mouse_pressed(button, x, y, clicks)
|
function DocView:on_mouse_pressed(button, x, y, clicks)
|
||||||
local caught = DocView.super.on_mouse_pressed(self, button, x, y, clicks)
|
local caught = DocView.super.on_mouse_pressed(self, button, x, y, clicks)
|
||||||
if caught then
|
if caught then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if keymap.modkeys["shift"] then
|
local line, col = self:resolve_screen_position(x, y)
|
||||||
if clicks == 1 then
|
if clicks == 2 then
|
||||||
local line1, col1 = select(3, self.doc:get_selection())
|
local line1, col1 = translate.start_of_word(self.doc, line, col)
|
||||||
local line2, col2 = self:resolve_screen_position(x, y)
|
local line2, col2 = translate.end_of_word(self.doc, line, col)
|
||||||
self.doc:set_selection(line2, col2, line1, col1)
|
self.doc:set_selection(line2, col2, line1, col1)
|
||||||
|
elseif clicks == 3 then
|
||||||
|
if line == #self.doc.lines then
|
||||||
|
self.doc:insert(math.huge, math.huge, "\n")
|
||||||
end
|
end
|
||||||
|
self.doc:set_selection(line + 1, 1, line, 1)
|
||||||
else
|
else
|
||||||
local line, col = self:resolve_screen_position(x, y)
|
local line2, col2
|
||||||
self.doc:set_selection(mouse_selection(self.doc, clicks, line, col, line, col))
|
if keymap.modkeys["shift"] then
|
||||||
self.mouse_selecting = { line, col, clicks = clicks }
|
line2, col2 = select(3, self.doc:get_selection())
|
||||||
|
end
|
||||||
|
self.doc:set_selection(line, col, line2, col2)
|
||||||
|
self.mouse_selecting = true
|
||||||
end
|
end
|
||||||
self.blink_timer = 0
|
self.blink_timer = 0
|
||||||
end
|
end
|
||||||
|
@ -243,17 +229,16 @@ function DocView:on_mouse_moved(x, y, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.mouse_selecting then
|
if self.mouse_selecting then
|
||||||
local l1, c1 = self:resolve_screen_position(x, y)
|
local _, _, line2, col2 = self.doc:get_selection()
|
||||||
local l2, c2 = table.unpack(self.mouse_selecting)
|
local line1, col1 = self:resolve_screen_position(x, y)
|
||||||
local clicks = self.mouse_selecting.clicks
|
self.doc:set_selection(line1, col1, line2, col2)
|
||||||
self.doc:set_selection(mouse_selection(self.doc, clicks, l1, c1, l2, c2))
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function DocView:on_mouse_released(button)
|
function DocView:on_mouse_released(button)
|
||||||
DocView.super.on_mouse_released(self, button)
|
DocView.super.on_mouse_released(self, button)
|
||||||
self.mouse_selecting = nil
|
self.mouse_selecting = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ local function project_scan_thread()
|
||||||
|
|
||||||
for _, file in ipairs(all) do
|
for _, file in ipairs(all) do
|
||||||
if not common.match_pattern(file, config.ignore_files) then
|
if not common.match_pattern(file, config.ignore_files) then
|
||||||
local file = (path ~= "." and path .. PATHSEP or "") .. file
|
local file = path .. PATHSEP .. file
|
||||||
local info = system.get_file_info(file)
|
local info = system.get_file_info(file)
|
||||||
if info and info.size < size_limit then
|
if info and info.size < size_limit then
|
||||||
info.filename = file
|
info.filename = file
|
||||||
|
@ -62,7 +62,7 @@ local function project_scan_thread()
|
||||||
while true do
|
while true do
|
||||||
-- get project files and replace previous table if the new table is
|
-- get project files and replace previous table if the new table is
|
||||||
-- different
|
-- different
|
||||||
local t = get_files(".")
|
local t = get_files(core.project_dir)
|
||||||
if diff_files(core.project_files, t) then
|
if diff_files(core.project_files, t) then
|
||||||
core.project_files = t
|
core.project_files = t
|
||||||
core.redraw = true
|
core.redraw = true
|
||||||
|
@ -82,26 +82,18 @@ function core.init()
|
||||||
CommandView = require "core.commandview"
|
CommandView = require "core.commandview"
|
||||||
Doc = require "core.doc"
|
Doc = require "core.doc"
|
||||||
|
|
||||||
local project_dir = EXEDIR
|
|
||||||
local files = {}
|
|
||||||
for i = 2, #ARGS do
|
|
||||||
local info = system.get_file_info(ARGS[i]) or {}
|
|
||||||
if info.type == "file" then
|
|
||||||
table.insert(files, system.absolute_path(ARGS[i]))
|
|
||||||
elseif info.type == "dir" then
|
|
||||||
project_dir = ARGS[i]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
system.chdir(project_dir)
|
|
||||||
|
|
||||||
core.frame_start = 0
|
core.frame_start = 0
|
||||||
core.clip_rect_stack = {{ 0,0,0,0 }}
|
core.clip_rect_stack = {{ 0,0,0,0 }}
|
||||||
core.log_items = {}
|
core.log_items = {}
|
||||||
core.docs = {}
|
core.docs = {}
|
||||||
core.threads = setmetatable({}, { __mode = "k" })
|
core.threads = setmetatable({}, { __mode = "k" })
|
||||||
core.project_files = {}
|
core.project_files = {}
|
||||||
core.redraw = true
|
core.project_dir = "."
|
||||||
|
|
||||||
|
local info = ARGS[2] and system.get_file_info(ARGS[2])
|
||||||
|
if info and info.type == "dir" then
|
||||||
|
core.project_dir = ARGS[2]:gsub("[\\/]$", "")
|
||||||
|
end
|
||||||
|
|
||||||
core.root_view = RootView()
|
core.root_view = RootView()
|
||||||
core.command_view = CommandView()
|
core.command_view = CommandView()
|
||||||
|
@ -109,6 +101,7 @@ function core.init()
|
||||||
|
|
||||||
core.root_view.root_node:split("down", core.command_view, true)
|
core.root_view.root_node:split("down", core.command_view, true)
|
||||||
core.root_view.root_node.b:split("down", core.status_view, true)
|
core.root_view.root_node.b:split("down", core.status_view, true)
|
||||||
|
core.active_view = core.root_view.root_node.a.active_view
|
||||||
|
|
||||||
core.add_thread(project_scan_thread)
|
core.add_thread(project_scan_thread)
|
||||||
command.add_defaults()
|
command.add_defaults()
|
||||||
|
@ -116,8 +109,12 @@ function core.init()
|
||||||
local got_user_error = not core.try(require, "user")
|
local got_user_error = not core.try(require, "user")
|
||||||
local got_project_error = not core.load_project_module()
|
local got_project_error = not core.load_project_module()
|
||||||
|
|
||||||
for _, filename in ipairs(files) do
|
for i = 2, #ARGS do
|
||||||
core.root_view:open_doc(core.open_doc(filename))
|
local filename = ARGS[i]
|
||||||
|
local info = system.get_file_info(filename)
|
||||||
|
if info and info.type == "file" then
|
||||||
|
core.root_view:open_doc(core.open_doc(filename))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if got_plugin_error or got_user_error or got_project_error then
|
if got_plugin_error or got_user_error or got_project_error then
|
||||||
|
@ -126,28 +123,8 @@ function core.init()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local temp_uid = (system.get_time() * 1000) % 0xffffffff
|
|
||||||
local temp_file_prefix = string.format(".lite_temp_%08x", temp_uid)
|
|
||||||
local temp_file_counter = 0
|
|
||||||
|
|
||||||
local function delete_temp_files()
|
|
||||||
for _, filename in ipairs(system.list_dir(EXEDIR)) do
|
|
||||||
if filename:find(temp_file_prefix, 1, true) == 1 then
|
|
||||||
os.remove(EXEDIR .. PATHSEP .. filename)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function core.temp_filename(ext)
|
|
||||||
temp_file_counter = temp_file_counter + 1
|
|
||||||
return EXEDIR .. PATHSEP .. temp_file_prefix
|
|
||||||
.. string.format("%06x", temp_file_counter) .. (ext or "")
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function core.quit(force)
|
function core.quit(force)
|
||||||
if force then
|
if force then
|
||||||
delete_temp_files()
|
|
||||||
os.exit()
|
os.exit()
|
||||||
end
|
end
|
||||||
local dirty_count = 0
|
local dirty_count = 0
|
||||||
|
@ -189,7 +166,7 @@ end
|
||||||
|
|
||||||
|
|
||||||
function core.load_project_module()
|
function core.load_project_module()
|
||||||
local filename = ".lite_project.lua"
|
local filename = core.project_dir .. "/.lite_project.lua"
|
||||||
if system.get_file_info(filename) then
|
if system.get_file_info(filename) then
|
||||||
return core.try(function()
|
return core.try(function()
|
||||||
local fn, err = loadfile(filename)
|
local fn, err = loadfile(filename)
|
||||||
|
@ -213,15 +190,6 @@ function core.reload_module(name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function core.set_active_view(view)
|
|
||||||
assert(view, "Tried to set active view to nil")
|
|
||||||
if view ~= core.active_view then
|
|
||||||
core.last_active_view = core.active_view
|
|
||||||
core.active_view = view
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function core.add_thread(f, weak_ref)
|
function core.add_thread(f, weak_ref)
|
||||||
local key = weak_ref or #core.threads + 1
|
local key = weak_ref or #core.threads + 1
|
||||||
local fn = function() return core.try(f) end
|
local fn = function() return core.try(f) end
|
||||||
|
@ -339,17 +307,11 @@ function core.on_event(type, ...)
|
||||||
elseif type == "mousewheel" then
|
elseif type == "mousewheel" then
|
||||||
core.root_view:on_mouse_wheel(...)
|
core.root_view:on_mouse_wheel(...)
|
||||||
elseif type == "filedropped" then
|
elseif type == "filedropped" then
|
||||||
local filename, mx, my = ...
|
local mx, my = core.root_view.mouse.x, core.root_view.mouse.y
|
||||||
local info = system.get_file_info(filename)
|
local ok, doc = core.try(core.open_doc, select(1, ...))
|
||||||
if info and info.type == "dir" then
|
if ok then
|
||||||
system.exec(string.format("%q %q", EXEFILE, filename))
|
core.root_view:on_mouse_pressed("left", mx, my, 1)
|
||||||
else
|
core.root_view:open_doc(doc)
|
||||||
local ok, doc = core.try(core.open_doc, filename)
|
|
||||||
if ok then
|
|
||||||
local node = core.root_view.root_node:get_child_overlapping_point(mx, my)
|
|
||||||
node:set_active_view(node.active_view)
|
|
||||||
core.root_view:open_doc(doc)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
elseif type == "quit" then
|
elseif type == "quit" then
|
||||||
core.quit()
|
core.quit()
|
||||||
|
@ -386,7 +348,10 @@ function core.step()
|
||||||
-- update
|
-- update
|
||||||
core.root_view.size.x, core.root_view.size.y = width, height
|
core.root_view.size.x, core.root_view.size.y = width, height
|
||||||
core.root_view:update()
|
core.root_view:update()
|
||||||
if not core.redraw then return false end
|
if not core.redraw then
|
||||||
|
if not system.window_has_focus() then system.wait_event(0.5) end
|
||||||
|
return
|
||||||
|
end
|
||||||
core.redraw = false
|
core.redraw = false
|
||||||
|
|
||||||
-- close unreferenced docs
|
-- close unreferenced docs
|
||||||
|
@ -400,10 +365,10 @@ function core.step()
|
||||||
|
|
||||||
-- update window title
|
-- update window title
|
||||||
local name = core.active_view:get_name()
|
local name = core.active_view:get_name()
|
||||||
local title = (name ~= "---") and (name .. " - lite") or "lite"
|
if name ~= "---" then
|
||||||
if title ~= core.window_title then
|
system.set_window_title(name .. " - lite")
|
||||||
system.set_window_title(title)
|
else
|
||||||
core.window_title = title
|
system.set_window_title("lite")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- draw
|
-- draw
|
||||||
|
@ -412,7 +377,6 @@ function core.step()
|
||||||
renderer.set_clip_rect(table.unpack(core.clip_rect_stack[1]))
|
renderer.set_clip_rect(table.unpack(core.clip_rect_stack[1]))
|
||||||
core.root_view:draw()
|
core.root_view:draw()
|
||||||
renderer.end_frame()
|
renderer.end_frame()
|
||||||
return true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -451,11 +415,8 @@ end)
|
||||||
function core.run()
|
function core.run()
|
||||||
while true do
|
while true do
|
||||||
core.frame_start = system.get_time()
|
core.frame_start = system.get_time()
|
||||||
local did_redraw = core.step()
|
core.step()
|
||||||
run_threads()
|
run_threads()
|
||||||
if not did_redraw and not system.window_has_focus() then
|
|
||||||
system.wait_event(0.25)
|
|
||||||
end
|
|
||||||
local elapsed = system.get_time() - core.frame_start
|
local elapsed = system.get_time() - core.frame_start
|
||||||
system.sleep(math.max(0, 1 / config.fps - elapsed))
|
system.sleep(math.max(0, 1 / config.fps - elapsed))
|
||||||
end
|
end
|
||||||
|
|
|
@ -84,8 +84,8 @@ end
|
||||||
|
|
||||||
|
|
||||||
keymap.add {
|
keymap.add {
|
||||||
["ctrl+shift+p"] = "core:find-command",
|
["ctrl+shift+p"] = "core:command-finder",
|
||||||
["ctrl+p"] = "core:find-file",
|
["ctrl+p"] = "core:file-finder",
|
||||||
["ctrl+o"] = "core:open-file",
|
["ctrl+o"] = "core:open-file",
|
||||||
["ctrl+n"] = "core:new-doc",
|
["ctrl+n"] = "core:new-doc",
|
||||||
["alt+return"] = "core:toggle-fullscreen",
|
["alt+return"] = "core:toggle-fullscreen",
|
||||||
|
@ -132,14 +132,13 @@ keymap.add {
|
||||||
["shift+tab"] = "doc:unindent",
|
["shift+tab"] = "doc:unindent",
|
||||||
["backspace"] = "doc:backspace",
|
["backspace"] = "doc:backspace",
|
||||||
["shift+backspace"] = "doc:backspace",
|
["shift+backspace"] = "doc:backspace",
|
||||||
["ctrl+backspace"] = "doc:delete-to-previous-word-start",
|
["ctrl+backspace"] = "doc:delete-to-previous-word-boundary",
|
||||||
["ctrl+shift+backspace"] = "doc:delete-to-previous-word-start",
|
["ctrl+shift+backspace"] = "doc:delete-to-previous-word-boundary",
|
||||||
["delete"] = "doc:delete",
|
["delete"] = "doc:delete",
|
||||||
["shift+delete"] = "doc:delete",
|
["shift+delete"] = "doc:delete",
|
||||||
["ctrl+delete"] = "doc:delete-to-next-word-end",
|
["ctrl+delete"] = "doc:delete-to-next-word-boundary",
|
||||||
["ctrl+shift+delete"] = "doc:delete-to-next-word-end",
|
["ctrl+shift+delete"] = "doc:delete-to-next-word-boundary",
|
||||||
["return"] = { "command:submit", "doc:newline" },
|
["return"] = { "command:submit", "doc:newline" },
|
||||||
["keypad enter"] = { "command:submit", "doc:newline" },
|
|
||||||
["ctrl+return"] = "doc:newline-below",
|
["ctrl+return"] = "doc:newline-below",
|
||||||
["ctrl+shift+return"] = "doc:newline-above",
|
["ctrl+shift+return"] = "doc:newline-above",
|
||||||
["ctrl+j"] = "doc:join-lines",
|
["ctrl+j"] = "doc:join-lines",
|
||||||
|
@ -156,10 +155,10 @@ keymap.add {
|
||||||
["right"] = "doc:move-to-next-char",
|
["right"] = "doc:move-to-next-char",
|
||||||
["up"] = { "command:select-previous", "doc:move-to-previous-line" },
|
["up"] = { "command:select-previous", "doc:move-to-previous-line" },
|
||||||
["down"] = { "command:select-next", "doc:move-to-next-line" },
|
["down"] = { "command:select-next", "doc:move-to-next-line" },
|
||||||
["ctrl+left"] = "doc:move-to-previous-word-start",
|
["ctrl+left"] = "doc:move-to-previous-word-boundary",
|
||||||
["ctrl+right"] = "doc:move-to-next-word-end",
|
["ctrl+right"] = "doc:move-to-next-word-boundary",
|
||||||
["ctrl+["] = "doc:move-to-previous-block-start",
|
["ctrl+["] = "doc:move-to-previous-start-of-block",
|
||||||
["ctrl+]"] = "doc:move-to-next-block-end",
|
["ctrl+]"] = "doc:move-to-next-start-of-block",
|
||||||
["home"] = "doc:move-to-start-of-line",
|
["home"] = "doc:move-to-start-of-line",
|
||||||
["end"] = "doc:move-to-end-of-line",
|
["end"] = "doc:move-to-end-of-line",
|
||||||
["ctrl+home"] = "doc:move-to-start-of-doc",
|
["ctrl+home"] = "doc:move-to-start-of-doc",
|
||||||
|
@ -171,10 +170,10 @@ keymap.add {
|
||||||
["shift+right"] = "doc:select-to-next-char",
|
["shift+right"] = "doc:select-to-next-char",
|
||||||
["shift+up"] = "doc:select-to-previous-line",
|
["shift+up"] = "doc:select-to-previous-line",
|
||||||
["shift+down"] = "doc:select-to-next-line",
|
["shift+down"] = "doc:select-to-next-line",
|
||||||
["ctrl+shift+left"] = "doc:select-to-previous-word-start",
|
["ctrl+shift+left"] = "doc:select-to-previous-word-boundary",
|
||||||
["ctrl+shift+right"] = "doc:select-to-next-word-end",
|
["ctrl+shift+right"] = "doc:select-to-next-word-boundary",
|
||||||
["ctrl+shift+["] = "doc:select-to-previous-block-start",
|
["ctrl+shift+["] = "doc:select-to-previous-start-of-block",
|
||||||
["ctrl+shift+]"] = "doc:select-to-next-block-end",
|
["ctrl+shift+]"] = "doc:select-to-next-start-of-block",
|
||||||
["shift+home"] = "doc:select-to-start-of-line",
|
["shift+home"] = "doc:select-to-start-of-line",
|
||||||
["shift+end"] = "doc:select-to-end-of-line",
|
["shift+end"] = "doc:select-to-end-of-line",
|
||||||
["ctrl+shift+home"] = "doc:select-to-start-of-doc",
|
["ctrl+shift+home"] = "doc:select-to-start-of-doc",
|
||||||
|
|
|
@ -9,33 +9,22 @@ local DocView = require "core.docview"
|
||||||
|
|
||||||
local EmptyView = View:extend()
|
local EmptyView = View:extend()
|
||||||
|
|
||||||
local function draw_text(x, y, color)
|
|
||||||
local th = style.big_font:get_height()
|
|
||||||
local dh = th + style.padding.y * 2
|
|
||||||
x = renderer.draw_text(style.big_font, "lite", x, y + (dh - th) / 2, color)
|
|
||||||
x = x + style.padding.x
|
|
||||||
renderer.draw_rect(x, y, math.ceil(1 * SCALE), dh, color)
|
|
||||||
local lines = {
|
|
||||||
{ fmt = "%s to run a command", cmd = "core:find-command" },
|
|
||||||
{ fmt = "%s to open a file from the project", cmd = "core:find-file" },
|
|
||||||
}
|
|
||||||
th = style.font:get_height()
|
|
||||||
y = y + (dh - th * 2 - style.padding.y) / 2
|
|
||||||
local w = 0
|
|
||||||
for _, line in ipairs(lines) do
|
|
||||||
local text = string.format(line.fmt, keymap.get_binding(line.cmd))
|
|
||||||
w = math.max(w, renderer.draw_text(style.font, text, x + style.padding.x, y, color))
|
|
||||||
y = y + th + style.padding.y
|
|
||||||
end
|
|
||||||
return w, dh
|
|
||||||
end
|
|
||||||
|
|
||||||
function EmptyView:draw()
|
function EmptyView:draw()
|
||||||
self:draw_background(style.background)
|
self:draw_background(style.background)
|
||||||
local w, h = draw_text(0, 0, { 0, 0, 0, 0 })
|
local pos = self.position
|
||||||
local x = self.position.x + math.max(style.padding.x, (self.size.x - w) / 2)
|
local x, y, w, h = pos.x, pos.y, self.size.x, self.size.y
|
||||||
local y = self.position.y + (self.size.y - h) / 2
|
local _, y = common.draw_text(style.big_font, style.dim, "empty", "center", x, y, w, h)
|
||||||
draw_text(x, y, style.dim)
|
local lines = {
|
||||||
|
{ fmt = "%s to run a command", cmd = "core:command-finder" },
|
||||||
|
{ fmt = "%s to open a file from the project", cmd = "core:file-finder" },
|
||||||
|
}
|
||||||
|
local th = style.font:get_height()
|
||||||
|
for _, line in ipairs(lines) do
|
||||||
|
local text = string.format(line.fmt, keymap.get_binding(line.cmd))
|
||||||
|
y = y + style.padding.y
|
||||||
|
common.draw_text(style.font, style.dim, text, "center", x, y, w, th)
|
||||||
|
y = y + th
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,18 +77,17 @@ end
|
||||||
local type_map = { up="vsplit", down="vsplit", left="hsplit", right="hsplit" }
|
local type_map = { up="vsplit", down="vsplit", left="hsplit", right="hsplit" }
|
||||||
|
|
||||||
function Node:split(dir, view, locked)
|
function Node:split(dir, view, locked)
|
||||||
assert(self.type == "leaf", "Tried to split non-leaf node")
|
assert(self.type == "leaf", "tried to split non-leaf node")
|
||||||
local type = assert(type_map[dir], "Invalid direction")
|
local type = assert(type_map[dir], "invalid direction")
|
||||||
local last_active = core.active_view
|
|
||||||
local child = Node()
|
local child = Node()
|
||||||
child:consume(self)
|
child:consume(self)
|
||||||
self:consume(Node(type))
|
self:consume(Node(type))
|
||||||
self.a = child
|
self.a = child
|
||||||
self.b = Node()
|
self.b = Node()
|
||||||
|
self.b.locked = locked
|
||||||
if view then self.b:add_view(view) end
|
if view then self.b:add_view(view) end
|
||||||
if locked then
|
if not self.b.active_view.focusable then
|
||||||
self.b.locked = locked
|
self.a:set_active_view(self.a.active_view)
|
||||||
core.set_active_view(last_active)
|
|
||||||
end
|
end
|
||||||
if dir == "up" or dir == "left" then
|
if dir == "up" or dir == "left" then
|
||||||
self.a, self.b = self.b, self.a
|
self.a, self.b = self.b, self.a
|
||||||
|
@ -130,15 +118,13 @@ function Node:close_active_view(root)
|
||||||
p:set_active_view(p.active_view)
|
p:set_active_view(p.active_view)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
core.last_active_view = nil
|
|
||||||
end
|
end
|
||||||
self.active_view:try_close(do_close)
|
self.active_view:try_close(do_close)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function Node:add_view(view)
|
function Node:add_view(view)
|
||||||
assert(self.type == "leaf", "Tried to add view to non-leaf node")
|
assert(self.type == "leaf", "tried to add view to non-leaf node")
|
||||||
assert(not self.locked, "Tried to add view to locked node")
|
|
||||||
if self.views[1] and self.views[1]:is(EmptyView) then
|
if self.views[1] and self.views[1]:is(EmptyView) then
|
||||||
table.remove(self.views)
|
table.remove(self.views)
|
||||||
end
|
end
|
||||||
|
@ -148,9 +134,9 @@ end
|
||||||
|
|
||||||
|
|
||||||
function Node:set_active_view(view)
|
function Node:set_active_view(view)
|
||||||
assert(self.type == "leaf", "Tried to set active view on non-leaf node")
|
assert(self.type == "leaf", "tried to set active view on non-leaf node")
|
||||||
self.active_view = view
|
self.active_view = view
|
||||||
core.set_active_view(view)
|
core.active_view = view
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -349,9 +335,7 @@ function Node:draw_tabs()
|
||||||
color = style.text
|
color = style.text
|
||||||
end
|
end
|
||||||
core.push_clip_rect(x, y, w, h)
|
core.push_clip_rect(x, y, w, h)
|
||||||
x, w = x + style.padding.x, w - style.padding.x * 2
|
common.draw_text(style.font, color, text, "center", x, y, w, h)
|
||||||
local align = style.font:get_width(text) > w and "left" or "center"
|
|
||||||
common.draw_text(style.font, color, text, align, x, y, w, h)
|
|
||||||
core.pop_clip_rect()
|
core.pop_clip_rect()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -393,16 +377,13 @@ end
|
||||||
|
|
||||||
|
|
||||||
function RootView:get_active_node()
|
function RootView:get_active_node()
|
||||||
return self.root_node:get_node_for_view(core.active_view)
|
local node = self.root_node:get_node_for_view(core.active_view)
|
||||||
|
return node or self.root_node.a
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function RootView:open_doc(doc)
|
function RootView:open_doc(doc)
|
||||||
local node = self:get_active_node()
|
local node = self:get_active_node()
|
||||||
if node.locked and core.last_active_view then
|
|
||||||
core.set_active_view(core.last_active_view)
|
|
||||||
node = self:get_active_node()
|
|
||||||
end
|
|
||||||
assert(not node.locked, "Cannot open doc on locked node")
|
assert(not node.locked, "Cannot open doc on locked node")
|
||||||
for i, view in ipairs(node.views) do
|
for i, view in ipairs(node.views) do
|
||||||
if view.doc == doc then
|
if view.doc == doc then
|
||||||
|
@ -432,7 +413,9 @@ function RootView:on_mouse_pressed(button, x, y, clicks)
|
||||||
node:close_active_view(self.root_node)
|
node:close_active_view(self.root_node)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
core.set_active_view(node.active_view)
|
if node.active_view.focusable then
|
||||||
|
core.active_view = node.active_view
|
||||||
|
end
|
||||||
node.active_view:on_mouse_pressed(button, x, y, clicks)
|
node.active_view:on_mouse_pressed(button, x, y, clicks)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -448,13 +431,13 @@ end
|
||||||
|
|
||||||
function RootView:on_mouse_moved(x, y, dx, dy)
|
function RootView:on_mouse_moved(x, y, dx, dy)
|
||||||
if self.dragged_divider then
|
if self.dragged_divider then
|
||||||
local node = self.dragged_divider
|
local div = self.dragged_divider
|
||||||
if node.type == "hsplit" then
|
if div.type == "hsplit" then
|
||||||
node.divider = node.divider + dx / node.size.x
|
div.divider = div.divider + dx / div.size.x
|
||||||
else
|
else
|
||||||
node.divider = node.divider + dy / node.size.y
|
div.divider = div.divider + dy / div.size.y
|
||||||
end
|
end
|
||||||
node.divider = common.clamp(node.divider, 0.01, 0.99)
|
div.divider = common.clamp(div.divider, 0.01, 0.99)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -16,13 +16,13 @@ StatusView.separator2 = " | "
|
||||||
|
|
||||||
function StatusView:new()
|
function StatusView:new()
|
||||||
StatusView.super.new(self)
|
StatusView.super.new(self)
|
||||||
|
self.focusable = false
|
||||||
self.message_timeout = 0
|
self.message_timeout = 0
|
||||||
self.message = {}
|
self.message = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function StatusView:on_mouse_pressed()
|
function StatusView:on_mouse_pressed()
|
||||||
core.set_active_view(core.last_active_view)
|
|
||||||
if system.get_time() < self.message_timeout
|
if system.get_time() < self.message_timeout
|
||||||
and not core.active_view:is(LogView) then
|
and not core.active_view:is(LogView) then
|
||||||
command.perform "core:open-log"
|
command.perform "core:open-log"
|
||||||
|
|
|
@ -11,19 +11,14 @@ function syntax.add(t)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function find(string, field)
|
function syntax.get(filename)
|
||||||
for i = #syntax.items, 1, -1 do
|
for i = #syntax.items, 1, -1 do
|
||||||
local t = syntax.items[i]
|
local t = syntax.items[i]
|
||||||
if common.match_pattern(string, t[field] or {}) then
|
if common.match_pattern(filename, t.files) then
|
||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
return plain_text_syntax
|
||||||
|
|
||||||
function syntax.get(filename, header)
|
|
||||||
return find(filename, "files")
|
|
||||||
or find(header, "headers")
|
|
||||||
or plain_text_syntax
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ function View:new()
|
||||||
self.scroll = { x = 0, y = 0, to = { x = 0, y = 0 } }
|
self.scroll = { x = 0, y = 0, to = { x = 0, y = 0 } }
|
||||||
self.cursor = "arrow"
|
self.cursor = "arrow"
|
||||||
self.scrollable = false
|
self.scrollable = false
|
||||||
|
self.focusable = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ local function reload_doc(doc)
|
||||||
|
|
||||||
local sel = { doc:get_selection() }
|
local sel = { doc:get_selection() }
|
||||||
doc:remove(1, 1, math.huge, math.huge)
|
doc:remove(1, 1, math.huge, math.huge)
|
||||||
doc:insert(1, 1, text:gsub("\r", ""):gsub("\n$", ""))
|
doc:insert(1, 1, text:gsub("\n$", ""))
|
||||||
doc:set_selection(table.unpack(sel))
|
doc:set_selection(table.unpack(sel))
|
||||||
|
|
||||||
update_time(doc)
|
update_time(doc)
|
||||||
|
|
|
@ -8,7 +8,6 @@ syntax.add {
|
||||||
{ pattern = { "/%*", "%*/" }, type = "comment" },
|
{ pattern = { "/%*", "%*/" }, type = "comment" },
|
||||||
{ pattern = { '"', '"', '\\' }, type = "string" },
|
{ pattern = { '"', '"', '\\' }, type = "string" },
|
||||||
{ pattern = { "'", "'", '\\' }, type = "string" },
|
{ pattern = { "'", "'", '\\' }, type = "string" },
|
||||||
{ pattern = { "`", "`", '\\' }, type = "string" },
|
|
||||||
{ pattern = "0x[%da-fA-F]+", type = "number" },
|
{ pattern = "0x[%da-fA-F]+", type = "number" },
|
||||||
{ pattern = "-?%d+[%d%.eE]*", type = "number" },
|
{ pattern = "-?%d+[%d%.eE]*", type = "number" },
|
||||||
{ pattern = "-?%.?%d+", type = "number" },
|
{ pattern = "-?%.?%d+", type = "number" },
|
||||||
|
@ -17,6 +16,7 @@ syntax.add {
|
||||||
{ pattern = "[%a_][%w_]*", type = "symbol" },
|
{ pattern = "[%a_][%w_]*", type = "symbol" },
|
||||||
},
|
},
|
||||||
symbols = {
|
symbols = {
|
||||||
|
["arguments"] = "keyword2",
|
||||||
["async"] = "keyword",
|
["async"] = "keyword",
|
||||||
["await"] = "keyword",
|
["await"] = "keyword",
|
||||||
["break"] = "keyword",
|
["break"] = "keyword",
|
||||||
|
@ -32,6 +32,7 @@ syntax.add {
|
||||||
["else"] = "keyword",
|
["else"] = "keyword",
|
||||||
["export"] = "keyword",
|
["export"] = "keyword",
|
||||||
["extends"] = "keyword",
|
["extends"] = "keyword",
|
||||||
|
["false"] = "literal",
|
||||||
["finally"] = "keyword",
|
["finally"] = "keyword",
|
||||||
["for"] = "keyword",
|
["for"] = "keyword",
|
||||||
["function"] = "keyword",
|
["function"] = "keyword",
|
||||||
|
@ -39,29 +40,26 @@ syntax.add {
|
||||||
["if"] = "keyword",
|
["if"] = "keyword",
|
||||||
["import"] = "keyword",
|
["import"] = "keyword",
|
||||||
["in"] = "keyword",
|
["in"] = "keyword",
|
||||||
|
["Infinity"] = "keyword2",
|
||||||
["instanceof"] = "keyword",
|
["instanceof"] = "keyword",
|
||||||
["let"] = "keyword",
|
["let"] = "keyword",
|
||||||
|
["NaN"] = "keyword2",
|
||||||
["new"] = "keyword",
|
["new"] = "keyword",
|
||||||
|
["null"] = "literal",
|
||||||
["return"] = "keyword",
|
["return"] = "keyword",
|
||||||
["set"] = "keyword",
|
["set"] = "keyword",
|
||||||
["static"] = "keyword",
|
|
||||||
["super"] = "keyword",
|
["super"] = "keyword",
|
||||||
["switch"] = "keyword",
|
["switch"] = "keyword",
|
||||||
|
["this"] = "keyword2",
|
||||||
["throw"] = "keyword",
|
["throw"] = "keyword",
|
||||||
|
["true"] = "literal",
|
||||||
["try"] = "keyword",
|
["try"] = "keyword",
|
||||||
["typeof"] = "keyword",
|
["typeof"] = "keyword",
|
||||||
|
["undefined"] = "literal",
|
||||||
["var"] = "keyword",
|
["var"] = "keyword",
|
||||||
["void"] = "keyword",
|
["void"] = "keyword",
|
||||||
["while"] = "keyword",
|
["while"] = "keyword",
|
||||||
["with"] = "keyword",
|
["with"] = "keyword",
|
||||||
["yield"] = "keyword",
|
["yield"] = "keyword",
|
||||||
["true"] = "literal",
|
|
||||||
["false"] = "literal",
|
|
||||||
["null"] = "literal",
|
|
||||||
["undefined"] = "literal",
|
|
||||||
["arguments"] = "keyword2",
|
|
||||||
["Infinity"] = "keyword2",
|
|
||||||
["NaN"] = "keyword2",
|
|
||||||
["this"] = "keyword2",
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ local syntax = require "core.syntax"
|
||||||
|
|
||||||
syntax.add {
|
syntax.add {
|
||||||
files = "%.lua$",
|
files = "%.lua$",
|
||||||
headers = "^#!.*[ /]lua",
|
|
||||||
comment = "--",
|
comment = "--",
|
||||||
patterns = {
|
patterns = {
|
||||||
{ pattern = { '"', '"', '\\' }, type = "string" },
|
{ pattern = { '"', '"', '\\' }, type = "string" },
|
||||||
|
@ -13,7 +12,6 @@ syntax.add {
|
||||||
{ pattern = "-?0x%x+", type = "number" },
|
{ pattern = "-?0x%x+", type = "number" },
|
||||||
{ pattern = "-?%d+[%d%.eE]*", type = "number" },
|
{ pattern = "-?%d+[%d%.eE]*", type = "number" },
|
||||||
{ pattern = "-?%.?%d+", type = "number" },
|
{ pattern = "-?%.?%d+", type = "number" },
|
||||||
{ pattern = "<%a+>", type = "keyword2" },
|
|
||||||
{ pattern = "%.%.%.?", type = "operator" },
|
{ pattern = "%.%.%.?", type = "operator" },
|
||||||
{ pattern = "[<>~=]=", type = "operator" },
|
{ pattern = "[<>~=]=", type = "operator" },
|
||||||
{ pattern = "[%+%-=/%*%^%%#<>]", type = "operator" },
|
{ pattern = "[%+%-=/%*%^%%#<>]", type = "operator" },
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
local syntax = require "core.syntax"
|
local syntax = require "core.syntax"
|
||||||
|
|
||||||
syntax.add {
|
syntax.add {
|
||||||
files = { "%.py$", "%.pyw$" },
|
files = "%.py$",
|
||||||
headers = "^#!.*[ /]python",
|
|
||||||
comment = "#",
|
comment = "#",
|
||||||
patterns = {
|
patterns = {
|
||||||
{ pattern = { "#", "\n" }, type = "comment" },
|
{ pattern = { "#", "\n" }, type = "comment" },
|
||||||
|
|
|
@ -2,7 +2,6 @@ local syntax = require "core.syntax"
|
||||||
|
|
||||||
syntax.add {
|
syntax.add {
|
||||||
files = { "%.xml$", "%.html?$" },
|
files = { "%.xml$", "%.html?$" },
|
||||||
headers = "<%?xml",
|
|
||||||
patterns = {
|
patterns = {
|
||||||
{ pattern = { "<!%-%-", "%-%->" }, type = "comment" },
|
{ pattern = { "<!%-%-", "%-%->" }, type = "comment" },
|
||||||
{ pattern = { '%f[^>][^<]', '%f[<]' }, type = "normal" },
|
{ pattern = { '%f[^>][^<]', '%f[<]' }, type = "normal" },
|
||||||
|
|
|
@ -22,6 +22,7 @@ local TreeView = View:extend()
|
||||||
function TreeView:new()
|
function TreeView:new()
|
||||||
TreeView.super.new(self)
|
TreeView.super.new(self)
|
||||||
self.scrollable = true
|
self.scrollable = true
|
||||||
|
self.focusable = false
|
||||||
self.visible = true
|
self.visible = true
|
||||||
self.init_size = true
|
self.init_size = true
|
||||||
self.cache = {}
|
self.cache = {}
|
||||||
|
@ -34,7 +35,7 @@ function TreeView:get_cached(item)
|
||||||
t = {}
|
t = {}
|
||||||
t.filename = item.filename
|
t.filename = item.filename
|
||||||
t.abs_filename = system.absolute_path(item.filename)
|
t.abs_filename = system.absolute_path(item.filename)
|
||||||
t.name = t.filename:match("[^\\/]+$")
|
t.path, t.name = t.filename:match("^(.*)[\\/](.+)$")
|
||||||
t.depth = get_depth(t.filename)
|
t.depth = get_depth(t.filename)
|
||||||
t.type = item.type
|
t.type = item.type
|
||||||
self.cache[t.filename] = t
|
self.cache[t.filename] = t
|
||||||
|
@ -142,6 +143,7 @@ function TreeView:draw()
|
||||||
|
|
||||||
local icon_width = style.icon_font:get_width("D")
|
local icon_width = style.icon_font:get_width("D")
|
||||||
local spacing = style.font:get_width(" ") * 2
|
local spacing = style.font:get_width(" ") * 2
|
||||||
|
local root_depth = get_depth(core.project_dir) + 1
|
||||||
|
|
||||||
local doc = core.active_view.doc
|
local doc = core.active_view.doc
|
||||||
local active_filename = doc and system.absolute_path(doc.filename or "")
|
local active_filename = doc and system.absolute_path(doc.filename or "")
|
||||||
|
@ -161,7 +163,7 @@ function TreeView:draw()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- icons
|
-- icons
|
||||||
x = x + item.depth * style.padding.x + style.padding.x
|
x = x + (item.depth - root_depth) * style.padding.x + style.padding.x
|
||||||
if item.type == "dir" then
|
if item.type == "dir" then
|
||||||
local icon1 = item.expanded and "-" or "+"
|
local icon1 = item.expanded and "-" or "+"
|
||||||
local icon2 = item.expanded and "D" or "d"
|
local icon2 = item.expanded and "D" or "d"
|
||||||
|
|
|
@ -4,16 +4,9 @@ local Doc = require "core.doc"
|
||||||
|
|
||||||
|
|
||||||
local function trim_trailing_whitespace(doc)
|
local function trim_trailing_whitespace(doc)
|
||||||
local cline, ccol = doc:get_selection()
|
|
||||||
for i = 1, #doc.lines do
|
for i = 1, #doc.lines do
|
||||||
local old_text = doc:get_text(i, 1, i, math.huge)
|
local old_text = doc:get_text(i, 1, i, math.huge)
|
||||||
local new_text = old_text:gsub("%s*$", "")
|
local new_text = old_text:gsub("%s*$", "")
|
||||||
|
|
||||||
-- don't remove whitespace which would cause the caret to reposition
|
|
||||||
if cline == i and ccol > #new_text then
|
|
||||||
new_text = old_text:sub(1, ccol - 1)
|
|
||||||
end
|
|
||||||
|
|
||||||
if old_text ~= new_text then
|
if old_text ~= new_text then
|
||||||
doc:insert(i, 1, new_text)
|
doc:insert(i, 1, new_text)
|
||||||
doc:remove(i, #new_text + 1, i, math.huge)
|
doc:remove(i, #new_text + 1, i, math.huge)
|
||||||
|
|
|
@ -5,7 +5,7 @@ style.background = { common.color "#fbfbfb" }
|
||||||
style.background2 = { common.color "#f2f2f2" }
|
style.background2 = { common.color "#f2f2f2" }
|
||||||
style.background3 = { common.color "#f2f2f2" }
|
style.background3 = { common.color "#f2f2f2" }
|
||||||
style.text = { common.color "#404040" }
|
style.text = { common.color "#404040" }
|
||||||
style.caret = { common.color "#fc1785" }
|
style.caret = { common.color "#181818" }
|
||||||
style.accent = { common.color "#fc1785" }
|
style.accent = { common.color "#fc1785" }
|
||||||
style.dim = { common.color "#b0b0b0" }
|
style.dim = { common.color "#b0b0b0" }
|
||||||
style.divider = { common.color "#e8e8e8" }
|
style.divider = { common.color "#e8e8e8" }
|
||||||
|
|
146
doc/usage.md
146
doc/usage.md
|
@ -1,146 +0,0 @@
|
||||||
# lite
|
|
||||||
|
|
||||||
![screenshot](https://user-images.githubusercontent.com/3920290/81471642-6c165880-91ea-11ea-8cd1-fae7ae8f0bc4.png)
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
lite is a lightweight text editor written mostly in Lua — it aims to provide
|
|
||||||
something practical, pretty, *small* and fast, implemented as simply as
|
|
||||||
possible; easy to modify and extend, or to use without doing either.
|
|
||||||
|
|
||||||
|
|
||||||
## Getting Started
|
|
||||||
When lite is started it's typically opened with a *project directory* — this
|
|
||||||
is the directory where your project's code and other data resides. The project
|
|
||||||
directory is set once when lite is started and, for the duration of the
|
|
||||||
session, cannot be changed.
|
|
||||||
|
|
||||||
To open lite with a specific project directory the directory name can be passed
|
|
||||||
as a command-line argument *(`.` can be passed to use the current directory)* or
|
|
||||||
the directory can be dragged onto either the lite executable or a running
|
|
||||||
instance of lite.
|
|
||||||
|
|
||||||
The main way of opening files in lite is through the `core:find-file` command
|
|
||||||
— this provides a fuzzy finder over all of the project's files and can be
|
|
||||||
opened using the **`ctrl+p`** shortcut by default.
|
|
||||||
|
|
||||||
Commands can be run using keyboard shortcuts, or by using the `core:find-command`
|
|
||||||
command bound to **`ctrl+shift+p`** by default. For example, pressing
|
|
||||||
`ctrl+shift+p` and typing `newdoc` then pressing `return` would open a new
|
|
||||||
document. The current keyboard shortcut for a command can be seen to the right
|
|
||||||
of the command name on the command finder, thus to find the shortcut for a command
|
|
||||||
`ctrl+shift+p` can be pressed and the command name typed.
|
|
||||||
|
|
||||||
|
|
||||||
## User Module
|
|
||||||
lite can be configured through use of the user module. The user module can be
|
|
||||||
used for changing options in the config module, adding additional key bindings,
|
|
||||||
loading custom color themes, modifying the style or changing any other part of
|
|
||||||
lite to your personal preference.
|
|
||||||
|
|
||||||
The user module is loaded by lite when the application starts, after the plugins
|
|
||||||
have been loaded.
|
|
||||||
|
|
||||||
The user module can be modified by running the `core:open-user-module` command
|
|
||||||
or otherwise directly opening the `data/user/init.lua` file.
|
|
||||||
|
|
||||||
|
|
||||||
## Project Module
|
|
||||||
The project module is an optional module which is loaded from the current
|
|
||||||
project's directory when lite is started. Project modules can be useful for
|
|
||||||
things like adding custom commands for project-specific build systems, or
|
|
||||||
loading project-specific plugins.
|
|
||||||
|
|
||||||
The project module is loaded by lite when the application starts, after both the
|
|
||||||
plugins and user module have been loaded.
|
|
||||||
|
|
||||||
The project module can be edited by running the `core:open-project-module`
|
|
||||||
command — if the module does not exist for the current project when the
|
|
||||||
command is run it will be created.
|
|
||||||
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
Commands in lite are used both through the command finder (`ctrl+shift+p`) and
|
|
||||||
by lite's keyboard shortcut system. Commands consist of 3 components:
|
|
||||||
* **Name** — The command name in the form of `namespace:action-name`, for
|
|
||||||
example: `doc:select-all`
|
|
||||||
* **Predicate** — A function that returns true if the command can be ran, for
|
|
||||||
example, for any document commands the predicate checks whether the active
|
|
||||||
view is a document
|
|
||||||
* **Function** — The function which performs the command itself
|
|
||||||
|
|
||||||
Commands can be added using the `command.add` function provided by the
|
|
||||||
`core.command` module:
|
|
||||||
```lua
|
|
||||||
local core = require "core"
|
|
||||||
local command = require "core.command"
|
|
||||||
|
|
||||||
command.add("core.docview", {
|
|
||||||
["doc:save"] = function()
|
|
||||||
core.active_view.doc:save()
|
|
||||||
core.log("Saved '%s', core.active_view.doc.filename)
|
|
||||||
end
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
Commands can be performed programatically (eg. from another command or by your
|
|
||||||
user module) by calling the `command.perform` function after requiring the
|
|
||||||
`command` module:
|
|
||||||
```lua
|
|
||||||
local command = require "core.command"
|
|
||||||
command.perform "core:quit"
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Keymap
|
|
||||||
All keyboard shortcuts in lite are handled by the `core.keymap` module. A key
|
|
||||||
binding in lite maps a "stroke" (eg. `ctrl+q`) to one or more commands (eg.
|
|
||||||
`core:quit`). When the shortcut is pressed lite will iterate each command
|
|
||||||
assigned to that key and run the *predicate function* for that command — if the
|
|
||||||
predicate passes it stops iterating and runs the command.
|
|
||||||
|
|
||||||
An example of where this used is the default binding of the `tab` key:
|
|
||||||
``` lua
|
|
||||||
["tab"] = { "command:complete", "doc:indent" },
|
|
||||||
```
|
|
||||||
When tab is pressed the `command:complete` command is attempted which will only
|
|
||||||
succeed if the command-input at the bottom of the window is active. Otherwise
|
|
||||||
the `doc:indent` command is attempted which will only succeed if we have a
|
|
||||||
document as our active view.
|
|
||||||
|
|
||||||
A new mapping can be added by your user module as follows:
|
|
||||||
```lua
|
|
||||||
local keymap = require "core.keymap"
|
|
||||||
keymap.add { ["ctrl+q"] = "core:quit" }
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Plugins
|
|
||||||
Plugins in lite are normal lua modules and are treated as such — no
|
|
||||||
complicated plugin manager is provided, and, once a plugin is loaded, it is never
|
|
||||||
expected be to have to unload itself.
|
|
||||||
|
|
||||||
To install a plugin simply drop it in the `data/plugins` directory — installed
|
|
||||||
plugins will be automatically loaded when lite starts. To uninstall a plugin the
|
|
||||||
plugin file can be deleted — any plugin (including those included with lite's
|
|
||||||
default installation) can be deleted to remove its functionality.
|
|
||||||
|
|
||||||
If you want to load a plugin only under a certain circumstance (for example,
|
|
||||||
only on a given project) the plugin can be placed somewhere other than the
|
|
||||||
`data/plugins` directory so that it is not automatically loaded. The plugin can
|
|
||||||
then be loaded manually as needed by using the `require` function.
|
|
||||||
|
|
||||||
Plugins can be downloaded from the [plugins repository](https://github.com/rxi/lite-plugins).
|
|
||||||
|
|
||||||
|
|
||||||
## Color Themes
|
|
||||||
Colors themes in lite are lua modules which overwrite the color fields of lite's
|
|
||||||
`core.style` module. Color themes should be placed in the `data/user/colors`
|
|
||||||
directory.
|
|
||||||
|
|
||||||
A color theme can be set by requiring it in your user module:
|
|
||||||
```lua
|
|
||||||
require "user.colors.winter"
|
|
||||||
```
|
|
||||||
|
|
||||||
Color themes can be downloaded from the [color themes repository](https://github.com/rxi/lite-colors).
|
|
||||||
|
|
49
lite.cbp
49
lite.cbp
|
@ -1,49 +0,0 @@
|
||||||
<?xml version="1.0" ?>
|
|
||||||
<CodeBench_Project name="lite" path="SDH3:Programming/workspace/MyProjects/lite/lite.cbp" created="1387049720" lastmodified="1387152257">
|
|
||||||
<plugin name="PROGDIR:Plugins/AmigaOS4SDK.CCPlugin" flags="0"/>
|
|
||||||
<target/>
|
|
||||||
<homedir name="SDH3:Programming/workspace/MyProjects/lite"/>
|
|
||||||
<includedir name="Applications:Programming/workspace/OtherProjects/lite/src"/>
|
|
||||||
<compiler name="gcc:bin/gcc" switches="-D__USE_INLINE__ -Wall -Werror -Wwrite-strings" stack="131072"/>
|
|
||||||
<linker switches="-lauto"/>
|
|
||||||
<debugger name="SDK:c/gdb"/>
|
|
||||||
<builder name="SDK:c/make -f"/>
|
|
||||||
<environment/>
|
|
||||||
<headers>
|
|
||||||
<file name="Applications:Programming/workspace/OtherProjects/lite/src/api/api.h" open="0"/>
|
|
||||||
<file name="Applications:Programming/workspace/OtherProjects/lite/src/rencache.h" open="0"/>
|
|
||||||
<file name="Applications:Programming/workspace/OtherProjects/lite/src/lib/stb/stb_truetype.h" open="0"/>
|
|
||||||
<file name="Applications:Programming/workspace/OtherProjects/lite/src/renderer.h" open="0"/>
|
|
||||||
</headers>
|
|
||||||
<sources>
|
|
||||||
<file name="src/api/api.c" open="0"/>
|
|
||||||
<file name="src/api/renderer.c" open="0"/>
|
|
||||||
<file name="src/api/renderer_font.c" open="0"/>
|
|
||||||
<file name="src/api/system.c" open="0"/>
|
|
||||||
<file name="src/main.c" open="1" current="1" top="75" left="0" line="97" row="16"/>
|
|
||||||
<file name="src/rencache.c" open="0"/>
|
|
||||||
<file name="src/renderer.c" open="0"/>
|
|
||||||
<file name="src/lib/stb/stb_truetype.c" open="0"/>
|
|
||||||
</sources>
|
|
||||||
<flags value="0x0000000000078005"/>
|
|
||||||
<buildscript name="Makefile" depth="3" open="0"/>
|
|
||||||
<projectnotes open="0"/>
|
|
||||||
<buildwindow open="0"/>
|
|
||||||
<targets>
|
|
||||||
<target name="lite" linker="gcc:bin/gcc" switches="-llua -lSDL2 -lpthread -lauto" flags="0x00000002">
|
|
||||||
<file name="src/lib/stb/stb_truetype.c"/>
|
|
||||||
<file name="src/api/renderer.c"/>
|
|
||||||
<file name="src/api/renderer_font.c"/>
|
|
||||||
<file name="src/api/system.c"/>
|
|
||||||
<file name="src/main.c"/>
|
|
||||||
<file name="src/api/api.c"/>
|
|
||||||
<file name="src/rencache.c"/>
|
|
||||||
<file name="src/renderer.c"/>
|
|
||||||
</target>
|
|
||||||
</targets>
|
|
||||||
<includepath>
|
|
||||||
<include path="src"/>
|
|
||||||
</includepath>
|
|
||||||
<logfile name="RAM Disk:Build.log"/>
|
|
||||||
<search lastsearch="stbtt_Scale" sensecase="1" replace_state="0"/>
|
|
||||||
</CodeBench_Project>
|
|
BIN
lite.cbp.info
BIN
lite.cbp.info
Binary file not shown.
|
@ -2,11 +2,9 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include "api.h"
|
#include "api.h"
|
||||||
#include "rencache.h"
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -37,7 +35,6 @@ static char* key_name(char *dst, int sym) {
|
||||||
|
|
||||||
static int f_poll_event(lua_State *L) {
|
static int f_poll_event(lua_State *L) {
|
||||||
char buf[16];
|
char buf[16];
|
||||||
int mx, my, wx, wy;
|
|
||||||
SDL_Event e;
|
SDL_Event e;
|
||||||
|
|
||||||
top:
|
top:
|
||||||
|
@ -57,9 +54,7 @@ top:
|
||||||
lua_pushnumber(L, e.window.data2);
|
lua_pushnumber(L, e.window.data2);
|
||||||
return 3;
|
return 3;
|
||||||
} else if (e.window.event == SDL_WINDOWEVENT_EXPOSED) {
|
} else if (e.window.event == SDL_WINDOWEVENT_EXPOSED) {
|
||||||
rencache_invalidate();
|
SDL_UpdateWindowSurface(window);
|
||||||
lua_pushstring(L, "exposed");
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
/* on some systems, when alt-tabbing to the window SDL will queue up
|
/* on some systems, when alt-tabbing to the window SDL will queue up
|
||||||
** several KEYDOWN events for the `tab` key; we flush all keydown
|
** several KEYDOWN events for the `tab` key; we flush all keydown
|
||||||
|
@ -70,14 +65,10 @@ top:
|
||||||
goto top;
|
goto top;
|
||||||
|
|
||||||
case SDL_DROPFILE:
|
case SDL_DROPFILE:
|
||||||
SDL_GetGlobalMouseState(&mx, &my);
|
|
||||||
SDL_GetWindowPosition(window, &wx, &wy);
|
|
||||||
lua_pushstring(L, "filedropped");
|
lua_pushstring(L, "filedropped");
|
||||||
lua_pushstring(L, e.drop.file);
|
lua_pushstring(L, e.drop.file);
|
||||||
lua_pushnumber(L, mx - wx);
|
|
||||||
lua_pushnumber(L, my - wy);
|
|
||||||
SDL_free(e.drop.file);
|
SDL_free(e.drop.file);
|
||||||
return 4;
|
return 2;
|
||||||
|
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
lua_pushstring(L, "keypressed");
|
lua_pushstring(L, "keypressed");
|
||||||
|
@ -225,14 +216,6 @@ static int f_show_confirm_dialog(lua_State *L) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int f_chdir(lua_State *L) {
|
|
||||||
const char *path = luaL_checkstring(L, 1);
|
|
||||||
int err = chdir(path);
|
|
||||||
if (err) { luaL_error(L, "chdir() failed"); }
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int f_list_dir(lua_State *L) {
|
static int f_list_dir(lua_State *L) {
|
||||||
const char *path = luaL_checkstring(L, 1);
|
const char *path = luaL_checkstring(L, 1);
|
||||||
|
|
||||||
|
@ -338,10 +321,10 @@ static int f_sleep(lua_State *L) {
|
||||||
static int f_exec(lua_State *L) {
|
static int f_exec(lua_State *L) {
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *cmd = luaL_checklstring(L, 1, &len);
|
const char *cmd = luaL_checklstring(L, 1, &len);
|
||||||
char *buf = malloc(len + 32);
|
char *buf = malloc(len + 16);
|
||||||
if (!buf) { luaL_error(L, "buffer allocation failed"); }
|
if (!buf) { luaL_error(L, "buffer allocation failed"); }
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
sprintf(buf, "cmd /c \"%s\"", cmd);
|
sprintf(buf, "cmd /c %s", cmd);
|
||||||
WinExec(buf, SW_HIDE);
|
WinExec(buf, SW_HIDE);
|
||||||
#else
|
#else
|
||||||
sprintf(buf, "%s &", cmd);
|
sprintf(buf, "%s &", cmd);
|
||||||
|
@ -363,11 +346,11 @@ static int f_fuzzy_match(lua_State *L) {
|
||||||
while (*str == ' ') { str++; }
|
while (*str == ' ') { str++; }
|
||||||
while (*ptn == ' ') { ptn++; }
|
while (*ptn == ' ') { ptn++; }
|
||||||
if (tolower(*str) == tolower(*ptn)) {
|
if (tolower(*str) == tolower(*ptn)) {
|
||||||
score += run * 10 - (*str != *ptn);
|
score += run;
|
||||||
run++;
|
run++;
|
||||||
ptn++;
|
ptn++;
|
||||||
} else {
|
} else {
|
||||||
score -= 10;
|
score--;
|
||||||
run = 0;
|
run = 0;
|
||||||
}
|
}
|
||||||
str++;
|
str++;
|
||||||
|
@ -387,7 +370,6 @@ static const luaL_Reg lib[] = {
|
||||||
{ "set_window_mode", f_set_window_mode },
|
{ "set_window_mode", f_set_window_mode },
|
||||||
{ "window_has_focus", f_window_has_focus },
|
{ "window_has_focus", f_window_has_focus },
|
||||||
{ "show_confirm_dialog", f_show_confirm_dialog },
|
{ "show_confirm_dialog", f_show_confirm_dialog },
|
||||||
{ "chdir", f_chdir },
|
|
||||||
{ "list_dir", f_list_dir },
|
{ "list_dir", f_list_dir },
|
||||||
{ "absolute_path", f_absolute_path },
|
{ "absolute_path", f_absolute_path },
|
||||||
{ "get_file_info", f_get_file_info },
|
{ "get_file_info", f_get_file_info },
|
||||||
|
|
|
@ -1,14 +1,5 @@
|
||||||
// stb_truetype.h - v1.24 - public domain
|
// stb_truetype.h - v1.19 - public domain
|
||||||
// authored from 2009-2020 by Sean Barrett / RAD Game Tools
|
// authored from 2009-2016 by Sean Barrett / RAD Game Tools
|
||||||
//
|
|
||||||
// =======================================================================
|
|
||||||
//
|
|
||||||
// NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES
|
|
||||||
//
|
|
||||||
// This library does no range checking of the offsets found in the file,
|
|
||||||
// meaning an attacker can use it to read arbitrary memory.
|
|
||||||
//
|
|
||||||
// =======================================================================
|
|
||||||
//
|
//
|
||||||
// This library processes TrueType files:
|
// This library processes TrueType files:
|
||||||
// parse files
|
// parse files
|
||||||
|
@ -41,11 +32,11 @@
|
||||||
// Daniel Ribeiro Maciel
|
// Daniel Ribeiro Maciel
|
||||||
//
|
//
|
||||||
// Bug/warning reports/fixes:
|
// Bug/warning reports/fixes:
|
||||||
// "Zer" on mollyrocket Fabian "ryg" Giesen github:NiLuJe
|
// "Zer" on mollyrocket Fabian "ryg" Giesen
|
||||||
// Cass Everitt Martins Mozeiko github:aloucks
|
// Cass Everitt Martins Mozeiko
|
||||||
// stoiko (Haemimont Games) Cap Petschulat github:oyvindjam
|
// stoiko (Haemimont Games) Cap Petschulat
|
||||||
// Brian Hook Omar Cornut github:vassvik
|
// Brian Hook Omar Cornut
|
||||||
// Walter van Niftrik Ryan Griege
|
// Walter van Niftrik github:aloucks
|
||||||
// David Gow Peter LaValle
|
// David Gow Peter LaValle
|
||||||
// David Given Sergey Popov
|
// David Given Sergey Popov
|
||||||
// Ivan-Assen Ivanov Giumo X. Clanjor
|
// Ivan-Assen Ivanov Giumo X. Clanjor
|
||||||
|
@ -53,16 +44,11 @@
|
||||||
// Johan Duparc Thomas Fields
|
// Johan Duparc Thomas Fields
|
||||||
// Hou Qiming Derek Vinyard
|
// Hou Qiming Derek Vinyard
|
||||||
// Rob Loach Cort Stratton
|
// Rob Loach Cort Stratton
|
||||||
// Kenney Phillis Jr. Brian Costabile
|
// Kenney Phillis Jr. github:oyvindjam
|
||||||
// Ken Voskuil (kaesve)
|
// Brian Costabile github:vassvik
|
||||||
//
|
//
|
||||||
// VERSION HISTORY
|
// VERSION HISTORY
|
||||||
//
|
//
|
||||||
// 1.24 (2020-02-05) fix warning
|
|
||||||
// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)
|
|
||||||
// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
|
|
||||||
// 1.21 (2019-02-25) fix warning
|
|
||||||
// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
|
|
||||||
// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod
|
// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod
|
||||||
// 1.18 (2018-01-29) add missing function
|
// 1.18 (2018-01-29) add missing function
|
||||||
// 1.17 (2017-07-23) make more arguments const; doc fix
|
// 1.17 (2017-07-23) make more arguments const; doc fix
|
||||||
|
@ -89,7 +75,7 @@
|
||||||
//
|
//
|
||||||
// USAGE
|
// USAGE
|
||||||
//
|
//
|
||||||
// Include this file in whatever places need to refer to it. In ONE C/C++
|
// Include this file in whatever places neeed to refer to it. In ONE C/C++
|
||||||
// file, write:
|
// file, write:
|
||||||
// #define STB_TRUETYPE_IMPLEMENTATION
|
// #define STB_TRUETYPE_IMPLEMENTATION
|
||||||
// before the #include of this file. This expands out the actual
|
// before the #include of this file. This expands out the actual
|
||||||
|
@ -256,6 +242,19 @@
|
||||||
// recommend it.
|
// recommend it.
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
// SOURCE STATISTICS (based on v0.6c, 2050 LOC)
|
||||||
|
//
|
||||||
|
// Documentation & header file 520 LOC \___ 660 LOC documentation
|
||||||
|
// Sample code 140 LOC /
|
||||||
|
// Truetype parsing 620 LOC ---- 620 LOC TrueType
|
||||||
|
// Software rasterization 240 LOC \ .
|
||||||
|
// Curve tesselation 120 LOC \__ 550 LOC Bitmap creation
|
||||||
|
// Bitmap management 100 LOC /
|
||||||
|
// Baked bitmap interface 70 LOC /
|
||||||
|
// Font name matching & access 150 LOC ---- 150
|
||||||
|
// C runtime library abstraction 60 LOC ---- 60
|
||||||
|
//
|
||||||
|
//
|
||||||
// PERFORMANCE MEASUREMENTS FOR 1.06:
|
// PERFORMANCE MEASUREMENTS FOR 1.06:
|
||||||
//
|
//
|
||||||
// 32-bit 64-bit
|
// 32-bit 64-bit
|
||||||
|
@ -557,8 +556,6 @@ STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int p
|
||||||
//
|
//
|
||||||
// It's inefficient; you might want to c&p it and optimize it.
|
// It's inefficient; you might want to c&p it and optimize it.
|
||||||
|
|
||||||
STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap);
|
|
||||||
// Query the font vertical metrics without having to create a font first.
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -644,12 +641,6 @@ STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h
|
||||||
// To use with PackFontRangesGather etc., you must set it before calls
|
// To use with PackFontRangesGather etc., you must set it before calls
|
||||||
// call to PackFontRangesGatherRects.
|
// call to PackFontRangesGatherRects.
|
||||||
|
|
||||||
STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip);
|
|
||||||
// If skip != 0, this tells stb_truetype to skip any codepoints for which
|
|
||||||
// there is no corresponding glyph. If skip=0, which is the default, then
|
|
||||||
// codepoints without a glyph recived the font's "missing character" glyph,
|
|
||||||
// typically an empty box by convention.
|
|
||||||
|
|
||||||
STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above
|
STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above
|
||||||
int char_index, // character to display
|
int char_index, // character to display
|
||||||
float *xpos, float *ypos, // pointers to current position in screen pixel space
|
float *xpos, float *ypos, // pointers to current position in screen pixel space
|
||||||
|
@ -678,7 +669,6 @@ struct stbtt_pack_context {
|
||||||
int height;
|
int height;
|
||||||
int stride_in_bytes;
|
int stride_in_bytes;
|
||||||
int padding;
|
int padding;
|
||||||
int skip_missing;
|
|
||||||
unsigned int h_oversample, v_oversample;
|
unsigned int h_oversample, v_oversample;
|
||||||
unsigned char *pixels;
|
unsigned char *pixels;
|
||||||
void *nodes;
|
void *nodes;
|
||||||
|
@ -704,7 +694,7 @@ STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);
|
||||||
// file will only define one font and it always be at offset 0, so it will
|
// file will only define one font and it always be at offset 0, so it will
|
||||||
// return '0' for index 0, and -1 for all other indices.
|
// return '0' for index 0, and -1 for all other indices.
|
||||||
|
|
||||||
// The following structure is defined publicly so you can declare one on
|
// The following structure is defined publically so you can declare one on
|
||||||
// the stack or as a global or etc, but you should treat it as opaque.
|
// the stack or as a global or etc, but you should treat it as opaque.
|
||||||
struct stbtt_fontinfo
|
struct stbtt_fontinfo
|
||||||
{
|
{
|
||||||
|
@ -714,7 +704,7 @@ struct stbtt_fontinfo
|
||||||
|
|
||||||
int numGlyphs; // number of glyphs, needed for range checking
|
int numGlyphs; // number of glyphs, needed for range checking
|
||||||
|
|
||||||
int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf
|
int loca,head,glyf,hhea,hmtx,kern,gpos; // table locations as offset from start of .ttf
|
||||||
int index_map; // a cmap mapping for our chosen character encoding
|
int index_map; // a cmap mapping for our chosen character encoding
|
||||||
int indexToLocFormat; // format needed to map from glyph index to glyph
|
int indexToLocFormat; // format needed to map from glyph index to glyph
|
||||||
|
|
||||||
|
@ -743,7 +733,6 @@ STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codep
|
||||||
// and you want a speed-up, call this function with the character you're
|
// and you want a speed-up, call this function with the character you're
|
||||||
// going to process, then use glyph-based functions instead of the
|
// going to process, then use glyph-based functions instead of the
|
||||||
// codepoint-based functions.
|
// codepoint-based functions.
|
||||||
// Returns 0 if the character codepoint is not defined in the font.
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -797,18 +786,6 @@ STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1,
|
||||||
STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
|
STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
|
||||||
// as above, but takes one or more glyph indices for greater efficiency
|
// as above, but takes one or more glyph indices for greater efficiency
|
||||||
|
|
||||||
typedef struct stbtt_kerningentry
|
|
||||||
{
|
|
||||||
int glyph1; // use stbtt_FindGlyphIndex
|
|
||||||
int glyph2;
|
|
||||||
int advance;
|
|
||||||
} stbtt_kerningentry;
|
|
||||||
|
|
||||||
STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info);
|
|
||||||
STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length);
|
|
||||||
// Retrieves a complete list of all of the kerning pairs provided by the font
|
|
||||||
// stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write.
|
|
||||||
// The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1)
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
|
@ -843,7 +820,7 @@ STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, s
|
||||||
// returns # of vertices and fills *vertices with the pointer to them
|
// returns # of vertices and fills *vertices with the pointer to them
|
||||||
// these are expressed in "unscaled" coordinates
|
// these are expressed in "unscaled" coordinates
|
||||||
//
|
//
|
||||||
// The shape is a series of contours. Each one starts with
|
// The shape is a series of countours. Each one starts with
|
||||||
// a STBTT_moveto, then consists of a series of mixed
|
// a STBTT_moveto, then consists of a series of mixed
|
||||||
// STBTT_lineto and STBTT_curveto segments. A lineto
|
// STBTT_lineto and STBTT_curveto segments. A lineto
|
||||||
// draws a line from previous endpoint to its x,y; a curveto
|
// draws a line from previous endpoint to its x,y; a curveto
|
||||||
|
@ -853,11 +830,6 @@ STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, s
|
||||||
STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);
|
STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);
|
||||||
// frees the data allocated above
|
// frees the data allocated above
|
||||||
|
|
||||||
STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg);
|
|
||||||
STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg);
|
|
||||||
// fills svg with the character's SVG data.
|
|
||||||
// returns data size or 0 if SVG not found.
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// BITMAP RENDERING
|
// BITMAP RENDERING
|
||||||
|
@ -944,7 +916,7 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
|
||||||
STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
|
STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
|
||||||
// These functions compute a discretized SDF field for a single character, suitable for storing
|
// These functions compute a discretized SDF field for a single character, suitable for storing
|
||||||
// in a single-channel texture, sampling with bilinear filtering, and testing against
|
// in a single-channel texture, sampling with bilinear filtering, and testing against
|
||||||
// larger than some threshold to produce scalable fonts.
|
// larger than some threshhold to produce scalable fonts.
|
||||||
// info -- the font
|
// info -- the font
|
||||||
// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap
|
// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap
|
||||||
// glyph/codepoint -- the character to generate the SDF for
|
// glyph/codepoint -- the character to generate the SDF for
|
||||||
|
@ -1359,22 +1331,6 @@ static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict)
|
||||||
return stbtt__cff_get_index(&cff);
|
return stbtt__cff_get_index(&cff);
|
||||||
}
|
}
|
||||||
|
|
||||||
// since most people won't use this, find this table the first time it's needed
|
|
||||||
static int stbtt__get_svg(stbtt_fontinfo *info)
|
|
||||||
{
|
|
||||||
stbtt_uint32 t;
|
|
||||||
if (info->svg < 0) {
|
|
||||||
t = stbtt__find_table(info->data, info->fontstart, "SVG ");
|
|
||||||
if (t) {
|
|
||||||
stbtt_uint32 offset = ttULONG(info->data + t + 2);
|
|
||||||
info->svg = t + offset;
|
|
||||||
} else {
|
|
||||||
info->svg = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return info->svg;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart)
|
static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart)
|
||||||
{
|
{
|
||||||
stbtt_uint32 cmap, t;
|
stbtt_uint32 cmap, t;
|
||||||
|
@ -1454,8 +1410,6 @@ static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, in
|
||||||
else
|
else
|
||||||
info->numGlyphs = 0xffff;
|
info->numGlyphs = 0xffff;
|
||||||
|
|
||||||
info->svg = -1;
|
|
||||||
|
|
||||||
// find a cmap encoding table we understand *now* to avoid searching
|
// find a cmap encoding table we understand *now* to avoid searching
|
||||||
// later. (todo: could make this installable)
|
// later. (todo: could make this installable)
|
||||||
// the same regardless of glyph.
|
// the same regardless of glyph.
|
||||||
|
@ -1804,7 +1758,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
|
num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
|
||||||
} else if (numberOfContours < 0) {
|
} else if (numberOfContours == -1) {
|
||||||
// Compound shapes.
|
// Compound shapes.
|
||||||
int more = 1;
|
int more = 1;
|
||||||
stbtt_uint8 *comp = data + g + 10;
|
stbtt_uint8 *comp = data + g + 10;
|
||||||
|
@ -1881,6 +1835,9 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
|
||||||
// More components ?
|
// More components ?
|
||||||
more = flags & (1<<5);
|
more = flags & (1<<5);
|
||||||
}
|
}
|
||||||
|
} else if (numberOfContours < 0) {
|
||||||
|
// @TODO other compound variations?
|
||||||
|
STBTT_assert(0);
|
||||||
} else {
|
} else {
|
||||||
// numberOfCounters == 0, do nothing
|
// numberOfCounters == 0, do nothing
|
||||||
}
|
}
|
||||||
|
@ -2309,48 +2266,6 @@ STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_inde
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info)
|
|
||||||
{
|
|
||||||
stbtt_uint8 *data = info->data + info->kern;
|
|
||||||
|
|
||||||
// we only look at the first table. it must be 'horizontal' and format 0.
|
|
||||||
if (!info->kern)
|
|
||||||
return 0;
|
|
||||||
if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
|
|
||||||
return 0;
|
|
||||||
if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return ttUSHORT(data+10);
|
|
||||||
}
|
|
||||||
|
|
||||||
STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length)
|
|
||||||
{
|
|
||||||
stbtt_uint8 *data = info->data + info->kern;
|
|
||||||
int k, length;
|
|
||||||
|
|
||||||
// we only look at the first table. it must be 'horizontal' and format 0.
|
|
||||||
if (!info->kern)
|
|
||||||
return 0;
|
|
||||||
if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
|
|
||||||
return 0;
|
|
||||||
if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
length = ttUSHORT(data+10);
|
|
||||||
if (table_length < length)
|
|
||||||
length = table_length;
|
|
||||||
|
|
||||||
for (k = 0; k < length; k++)
|
|
||||||
{
|
|
||||||
table[k].glyph1 = ttUSHORT(data+18+(k*6));
|
|
||||||
table[k].glyph2 = ttUSHORT(data+20+(k*6));
|
|
||||||
table[k].advance = ttSHORT(data+22+(k*6));
|
|
||||||
}
|
|
||||||
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
|
static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
|
||||||
{
|
{
|
||||||
stbtt_uint8 *data = info->data + info->kern;
|
stbtt_uint8 *data = info->data + info->kern;
|
||||||
|
@ -2548,7 +2463,6 @@ static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, i
|
||||||
if (valueFormat2 != 0) return 0;
|
if (valueFormat2 != 0) return 0;
|
||||||
|
|
||||||
STBTT_assert(coverageIndex < pairSetCount);
|
STBTT_assert(coverageIndex < pairSetCount);
|
||||||
STBTT__NOTUSED(pairSetCount);
|
|
||||||
|
|
||||||
needle=glyph2;
|
needle=glyph2;
|
||||||
r=pairValueCount-1;
|
r=pairValueCount-1;
|
||||||
|
@ -2626,7 +2540,8 @@ STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int
|
||||||
|
|
||||||
if (info->gpos)
|
if (info->gpos)
|
||||||
xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);
|
xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);
|
||||||
else if (info->kern)
|
|
||||||
|
if (info->kern)
|
||||||
xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);
|
xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);
|
||||||
|
|
||||||
return xAdvance;
|
return xAdvance;
|
||||||
|
@ -2687,45 +2602,6 @@ STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)
|
||||||
STBTT_free(v, info->userdata);
|
STBTT_free(v, info->userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
stbtt_uint8 *data = info->data;
|
|
||||||
stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info);
|
|
||||||
|
|
||||||
int numEntries = ttUSHORT(svg_doc_list);
|
|
||||||
stbtt_uint8 *svg_docs = svg_doc_list + 2;
|
|
||||||
|
|
||||||
for(i=0; i<numEntries; i++) {
|
|
||||||
stbtt_uint8 *svg_doc = svg_docs + (12 * i);
|
|
||||||
if ((gl >= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2)))
|
|
||||||
return svg_doc;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg)
|
|
||||||
{
|
|
||||||
stbtt_uint8 *data = info->data;
|
|
||||||
stbtt_uint8 *svg_doc;
|
|
||||||
|
|
||||||
if (info->svg == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
svg_doc = stbtt_FindSVGDoc(info, gl);
|
|
||||||
if (svg_doc != NULL) {
|
|
||||||
*svg = (char *) data + info->svg + ttULONG(svg_doc + 4);
|
|
||||||
return ttULONG(svg_doc + 8);
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg)
|
|
||||||
{
|
|
||||||
return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// antialiasing software rasterizer
|
// antialiasing software rasterizer
|
||||||
|
@ -3284,13 +3160,7 @@ static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e,
|
||||||
if (e->y0 != e->y1) {
|
if (e->y0 != e->y1) {
|
||||||
stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);
|
stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);
|
||||||
if (z != NULL) {
|
if (z != NULL) {
|
||||||
if (j == 0 && off_y != 0) {
|
STBTT_assert(z->ey >= scan_y_top);
|
||||||
if (z->ey < scan_y_top) {
|
|
||||||
// this can happen due to subpixel positioning and some kind of fp rounding error i think
|
|
||||||
z->ey = scan_y_top;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds
|
|
||||||
// insert at front
|
// insert at front
|
||||||
z->next = active;
|
z->next = active;
|
||||||
active = z;
|
active = z;
|
||||||
|
@ -3359,7 +3229,7 @@ static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n)
|
||||||
|
|
||||||
static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n)
|
static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n)
|
||||||
{
|
{
|
||||||
/* threshold for transitioning to insertion sort */
|
/* threshhold for transitioning to insertion sort */
|
||||||
while (n > 12) {
|
while (n > 12) {
|
||||||
stbtt__edge t;
|
stbtt__edge t;
|
||||||
int c01,c12,c,m,i,j;
|
int c01,c12,c,m,i,j;
|
||||||
|
@ -3494,7 +3364,7 @@ static void stbtt__add_point(stbtt__point *points, int n, float x, float y)
|
||||||
points[n].y = y;
|
points[n].y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
// tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching
|
// tesselate until threshhold p is happy... @TODO warped to compensate for non-linear stretching
|
||||||
static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n)
|
static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n)
|
||||||
{
|
{
|
||||||
// midpoint
|
// midpoint
|
||||||
|
@ -3919,7 +3789,6 @@ STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, in
|
||||||
spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw;
|
spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw;
|
||||||
spc->h_oversample = 1;
|
spc->h_oversample = 1;
|
||||||
spc->v_oversample = 1;
|
spc->v_oversample = 1;
|
||||||
spc->skip_missing = 0;
|
|
||||||
|
|
||||||
stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);
|
stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);
|
||||||
|
|
||||||
|
@ -3945,11 +3814,6 @@ STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h
|
||||||
spc->v_oversample = v_oversample;
|
spc->v_oversample = v_oversample;
|
||||||
}
|
}
|
||||||
|
|
||||||
STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip)
|
|
||||||
{
|
|
||||||
spc->skip_missing = skip;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1)
|
#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1)
|
||||||
|
|
||||||
static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)
|
static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)
|
||||||
|
@ -4092,7 +3956,6 @@ static float stbtt__oversample_shift(int oversample)
|
||||||
STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
|
STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
|
||||||
{
|
{
|
||||||
int i,j,k;
|
int i,j,k;
|
||||||
int missing_glyph_added = 0;
|
|
||||||
|
|
||||||
k=0;
|
k=0;
|
||||||
for (i=0; i < num_ranges; ++i) {
|
for (i=0; i < num_ranges; ++i) {
|
||||||
|
@ -4104,19 +3967,13 @@ STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stb
|
||||||
int x0,y0,x1,y1;
|
int x0,y0,x1,y1;
|
||||||
int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
|
int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
|
||||||
int glyph = stbtt_FindGlyphIndex(info, codepoint);
|
int glyph = stbtt_FindGlyphIndex(info, codepoint);
|
||||||
if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) {
|
stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,
|
||||||
rects[k].w = rects[k].h = 0;
|
scale * spc->h_oversample,
|
||||||
} else {
|
scale * spc->v_oversample,
|
||||||
stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,
|
0,0,
|
||||||
scale * spc->h_oversample,
|
&x0,&y0,&x1,&y1);
|
||||||
scale * spc->v_oversample,
|
rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);
|
||||||
0,0,
|
rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);
|
||||||
&x0,&y0,&x1,&y1);
|
|
||||||
rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);
|
|
||||||
rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);
|
|
||||||
if (glyph == 0)
|
|
||||||
missing_glyph_added = 1;
|
|
||||||
}
|
|
||||||
++k;
|
++k;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4150,7 +4007,7 @@ STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info
|
||||||
// rects array must be big enough to accommodate all characters in the given ranges
|
// rects array must be big enough to accommodate all characters in the given ranges
|
||||||
STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
|
STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
|
||||||
{
|
{
|
||||||
int i,j,k, missing_glyph = -1, return_value = 1;
|
int i,j,k, return_value = 1;
|
||||||
|
|
||||||
// save current values
|
// save current values
|
||||||
int old_h_over = spc->h_oversample;
|
int old_h_over = spc->h_oversample;
|
||||||
|
@ -4169,7 +4026,7 @@ STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const
|
||||||
sub_y = stbtt__oversample_shift(spc->v_oversample);
|
sub_y = stbtt__oversample_shift(spc->v_oversample);
|
||||||
for (j=0; j < ranges[i].num_chars; ++j) {
|
for (j=0; j < ranges[i].num_chars; ++j) {
|
||||||
stbrp_rect *r = &rects[k];
|
stbrp_rect *r = &rects[k];
|
||||||
if (r->was_packed && r->w != 0 && r->h != 0) {
|
if (r->was_packed) {
|
||||||
stbtt_packedchar *bc = &ranges[i].chardata_for_range[j];
|
stbtt_packedchar *bc = &ranges[i].chardata_for_range[j];
|
||||||
int advance, lsb, x0,y0,x1,y1;
|
int advance, lsb, x0,y0,x1,y1;
|
||||||
int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
|
int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
|
||||||
|
@ -4215,13 +4072,6 @@ STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const
|
||||||
bc->yoff = (float) y0 * recip_v + sub_y;
|
bc->yoff = (float) y0 * recip_v + sub_y;
|
||||||
bc->xoff2 = (x0 + r->w) * recip_h + sub_x;
|
bc->xoff2 = (x0 + r->w) * recip_h + sub_x;
|
||||||
bc->yoff2 = (y0 + r->h) * recip_v + sub_y;
|
bc->yoff2 = (y0 + r->h) * recip_v + sub_y;
|
||||||
|
|
||||||
if (glyph == 0)
|
|
||||||
missing_glyph = j;
|
|
||||||
} else if (spc->skip_missing) {
|
|
||||||
return_value = 0;
|
|
||||||
} else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) {
|
|
||||||
ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph];
|
|
||||||
} else {
|
} else {
|
||||||
return_value = 0; // if any fail, report failure
|
return_value = 0; // if any fail, report failure
|
||||||
}
|
}
|
||||||
|
@ -4290,19 +4140,6 @@ STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *
|
||||||
return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1);
|
return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap)
|
|
||||||
{
|
|
||||||
int i_ascent, i_descent, i_lineGap;
|
|
||||||
float scale;
|
|
||||||
stbtt_fontinfo info;
|
|
||||||
stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index));
|
|
||||||
scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size);
|
|
||||||
stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap);
|
|
||||||
*ascent = (float) i_ascent * scale;
|
|
||||||
*descent = (float) i_descent * scale;
|
|
||||||
*lineGap = (float) i_lineGap * scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer)
|
STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer)
|
||||||
{
|
{
|
||||||
float ipw = 1.0f / pw, iph = 1.0f / ph;
|
float ipw = 1.0f / pw, iph = 1.0f / ph;
|
||||||
|
@ -4523,7 +4360,12 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
|
||||||
int w,h;
|
int w,h;
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
|
|
||||||
if (scale == 0) return NULL;
|
// if one scale is 0, use same scale for both
|
||||||
|
if (scale_x == 0) scale_x = scale_y;
|
||||||
|
if (scale_y == 0) {
|
||||||
|
if (scale_x == 0) return NULL; // if both scales are 0, return NULL
|
||||||
|
scale_y = scale_x;
|
||||||
|
}
|
||||||
|
|
||||||
stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);
|
stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);
|
||||||
|
|
||||||
|
|
13
src/main.c
13
src/main.c
|
@ -20,6 +20,8 @@ static double get_scale(void) {
|
||||||
SDL_GetDisplayDPI(0, NULL, &dpi, NULL);
|
SDL_GetDisplayDPI(0, NULL, &dpi, NULL);
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
return dpi / 96.0;
|
return dpi / 96.0;
|
||||||
|
#elif __APPLE__
|
||||||
|
return 1.0; /* dpi / 72.0; */
|
||||||
#else
|
#else
|
||||||
return 1.0;
|
return 1.0;
|
||||||
#endif
|
#endif
|
||||||
|
@ -38,9 +40,6 @@ static void get_exe_filename(char *buf, int sz) {
|
||||||
#elif __APPLE__
|
#elif __APPLE__
|
||||||
unsigned size = sz;
|
unsigned size = sz;
|
||||||
_NSGetExecutablePath(buf, &size);
|
_NSGetExecutablePath(buf, &size);
|
||||||
#elif __amigaos4__
|
|
||||||
// TODO: Temporary. Needs to be done properly
|
|
||||||
strcpy(buf, "Applications:Programming/workspace/MyProjects/lite/lite");
|
|
||||||
#else
|
#else
|
||||||
strcpy(buf, "./lite");
|
strcpy(buf, "./lite");
|
||||||
#endif
|
#endif
|
||||||
|
@ -75,10 +74,6 @@ int main(int argc, char **argv) {
|
||||||
SDL_EnableScreenSaver();
|
SDL_EnableScreenSaver();
|
||||||
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
|
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
|
||||||
atexit(SDL_Quit);
|
atexit(SDL_Quit);
|
||||||
|
|
||||||
#ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR /* Available since 2.0.8 */
|
|
||||||
SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0");
|
|
||||||
#endif
|
|
||||||
#if SDL_VERSION_ATLEAST(2, 0, 5)
|
#if SDL_VERSION_ATLEAST(2, 0, 5)
|
||||||
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
|
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
|
||||||
#endif
|
#endif
|
||||||
|
@ -105,7 +100,7 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
lua_setglobal(L, "ARGS");
|
lua_setglobal(L, "ARGS");
|
||||||
|
|
||||||
lua_pushstring(L, "1.11");
|
lua_pushstring(L, "1.04");
|
||||||
lua_setglobal(L, "VERSION");
|
lua_setglobal(L, "VERSION");
|
||||||
|
|
||||||
lua_pushstring(L, SDL_GetPlatform());
|
lua_pushstring(L, SDL_GetPlatform());
|
||||||
|
@ -125,7 +120,7 @@ int main(int argc, char **argv) {
|
||||||
"xpcall(function()\n"
|
"xpcall(function()\n"
|
||||||
" SCALE = tonumber(os.getenv(\"LITE_SCALE\")) or SCALE\n"
|
" SCALE = tonumber(os.getenv(\"LITE_SCALE\")) or SCALE\n"
|
||||||
" PATHSEP = package.config:sub(1, 1)\n"
|
" PATHSEP = package.config:sub(1, 1)\n"
|
||||||
" EXEDIR = EXEFILE:match(\"^(.+)[/\\\\].*$\")\n"
|
" EXEDIR = EXEFILE:match(\"^(.-)[^/\\\\]*$\")"
|
||||||
" package.path = EXEDIR .. '/data/?.lua;' .. package.path\n"
|
" package.path = EXEDIR .. '/data/?.lua;' .. package.path\n"
|
||||||
" package.path = EXEDIR .. '/data/?/init.lua;' .. package.path\n"
|
" package.path = EXEDIR .. '/data/?/init.lua;' .. package.path\n"
|
||||||
" core = require('core')\n"
|
" core = require('core')\n"
|
||||||
|
|
|
@ -18,7 +18,6 @@ typedef struct {
|
||||||
RenRect rect;
|
RenRect rect;
|
||||||
RenColor color;
|
RenColor color;
|
||||||
RenFont *font;
|
RenFont *font;
|
||||||
int tab_width;
|
|
||||||
char text[0];
|
char text[0];
|
||||||
} Command;
|
} Command;
|
||||||
|
|
||||||
|
@ -144,7 +143,6 @@ int rencache_draw_text(RenFont *font, const char *text, int x, int y, RenColor c
|
||||||
cmd->color = color;
|
cmd->color = color;
|
||||||
cmd->font = font;
|
cmd->font = font;
|
||||||
cmd->rect = rect;
|
cmd->rect = rect;
|
||||||
cmd->tab_width = ren_get_font_tab_width(font);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,11 +150,6 @@ int rencache_draw_text(RenFont *font, const char *text, int x, int y, RenColor c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void rencache_invalidate(void) {
|
|
||||||
memset(cells_prev, 0xff, sizeof(cells_buf1));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void rencache_begin_frame(void) {
|
void rencache_begin_frame(void) {
|
||||||
/* reset all cells if the screen width/height has changed */
|
/* reset all cells if the screen width/height has changed */
|
||||||
int w, h;
|
int w, h;
|
||||||
|
@ -164,7 +157,7 @@ void rencache_begin_frame(void) {
|
||||||
if (screen_rect.width != w || h != screen_rect.height) {
|
if (screen_rect.width != w || h != screen_rect.height) {
|
||||||
screen_rect.width = w;
|
screen_rect.width = w;
|
||||||
screen_rect.height = h;
|
screen_rect.height = h;
|
||||||
rencache_invalidate();
|
memset(cells_prev, 0xff, sizeof(cells_buf1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,7 +249,6 @@ void rencache_end_frame(void) {
|
||||||
ren_draw_rect(cmd->rect, cmd->color);
|
ren_draw_rect(cmd->rect, cmd->color);
|
||||||
break;
|
break;
|
||||||
case DRAW_TEXT:
|
case DRAW_TEXT:
|
||||||
ren_set_font_tab_width(cmd->font, cmd->tab_width);
|
|
||||||
ren_draw_text(cmd->font, cmd->text, cmd->rect.x, cmd->rect.y, cmd->color);
|
ren_draw_text(cmd->font, cmd->text, cmd->rect.x, cmd->rect.y, cmd->color);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ void rencache_free_font(RenFont *font);
|
||||||
void rencache_set_clip_rect(RenRect rect);
|
void rencache_set_clip_rect(RenRect rect);
|
||||||
void rencache_draw_rect(RenRect rect, RenColor color);
|
void rencache_draw_rect(RenRect rect, RenColor color);
|
||||||
int rencache_draw_text(RenFont *font, const char *text, int x, int y, RenColor color);
|
int rencache_draw_text(RenFont *font, const char *text, int x, int y, RenColor color);
|
||||||
void rencache_invalidate(void);
|
|
||||||
void rencache_begin_frame(void);
|
void rencache_begin_frame(void);
|
||||||
void rencache_end_frame(void);
|
void rencache_end_frame(void);
|
||||||
|
|
||||||
|
|
|
@ -222,12 +222,6 @@ void ren_set_font_tab_width(RenFont *font, int n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int ren_get_font_tab_width(RenFont *font) {
|
|
||||||
GlyphSet *set = get_glyphset(font, '\t');
|
|
||||||
return set->glyphs['\t'].xadvance;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int ren_get_font_width(RenFont *font, const char *text) {
|
int ren_get_font_width(RenFont *font, const char *text) {
|
||||||
int x = 0;
|
int x = 0;
|
||||||
const char *p = text;
|
const char *p = text;
|
||||||
|
@ -270,7 +264,7 @@ static inline RenColor blend_pixel2(RenColor dst, RenColor src, RenColor color)
|
||||||
for (int j = y1; j < y2; j++) { \
|
for (int j = y1; j < y2; j++) { \
|
||||||
for (int i = x1; i < x2; i++) { \
|
for (int i = x1; i < x2; i++) { \
|
||||||
*d = expr; \
|
*d = expr; \
|
||||||
d++; \
|
d++; \
|
||||||
} \
|
} \
|
||||||
d += dr; \
|
d += dr; \
|
||||||
}
|
}
|
||||||
|
@ -284,22 +278,17 @@ void ren_draw_rect(RenRect rect, RenColor color) {
|
||||||
int y2 = rect.y + rect.height;
|
int y2 = rect.y + rect.height;
|
||||||
x2 = x2 > clip.right ? clip.right : x2;
|
x2 = x2 > clip.right ? clip.right : x2;
|
||||||
y2 = y2 > clip.bottom ? clip.bottom : y2;
|
y2 = y2 > clip.bottom ? clip.bottom : y2;
|
||||||
printf("DBG: rect\tx1: %d\ty1: %d\tx2:%d\ty2:%d\n", x1, y1, x2, y2);
|
|
||||||
SDL_Surface *surf = SDL_GetWindowSurface(window);
|
SDL_Surface *surf = SDL_GetWindowSurface(window);
|
||||||
RenColor *d = (RenColor*) surf->pixels;
|
RenColor *d = (RenColor*) surf->pixels;
|
||||||
printf("DBG: surf\tr: %d\tg: %d\tb:%d\ta:%d\tw: %d\n", d->r, d->g, d->b, d->a, surf->w);
|
d += x1 + y1 * surf->w;
|
||||||
d += x1 + y1 * (surf->pitch / 4);
|
int dr = surf->w - (x2 - x1);
|
||||||
//printf("DBG: surf\tr: %d\tg: %d\tb:%d\ta:%d\n", d->r, d->g, d->b, d->a);
|
|
||||||
int dr = (surf->pitch / 4) - (x2 - x1);
|
|
||||||
printf("DBG: r: %d\tg: %d\tb:%d\ta:%d\n", color.r, color.g, color.b, color.a);
|
|
||||||
if (color.a == 0xff) {
|
if (color.a == 0xff) {
|
||||||
//rect_draw_loop(color);
|
rect_draw_loop(color);
|
||||||
SDL_Rect rect = { x1, y1, x2 - x1, y2 - y1 };
|
|
||||||
SDL_FillRect(surf, &rect, SDL_MapRGBA(surf->format, color.r, color.g, color.b, color.a));
|
|
||||||
} else {
|
} else {
|
||||||
rect_draw_loop(blend_pixel(*d, color));
|
rect_draw_loop(blend_pixel(*d, color));
|
||||||
}
|
}
|
||||||
printf("======================\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@ void ren_free_image(RenImage *image);
|
||||||
RenFont* ren_load_font(const char *filename, float size);
|
RenFont* ren_load_font(const char *filename, float size);
|
||||||
void ren_free_font(RenFont *font);
|
void ren_free_font(RenFont *font);
|
||||||
void ren_set_font_tab_width(RenFont *font, int n);
|
void ren_set_font_tab_width(RenFont *font, int n);
|
||||||
int ren_get_font_tab_width(RenFont *font);
|
|
||||||
int ren_get_font_width(RenFont *font, const char *text);
|
int ren_get_font_width(RenFont *font, const char *text);
|
||||||
int ren_get_font_height(RenFont *font);
|
int ren_get_font_height(RenFont *font);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue