diff --git a/bin/choco.cmd b/bin/choco.cmd index beb9dac..165ebc5 100644 --- a/bin/choco.cmd +++ b/bin/choco.cmd @@ -1,4 +1,5 @@ @echo off where choco.exe >nul 2>nul -if errorlevel 1 powershell -c "Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))" +if errorlevel 1 powershell -c "Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1').Replace('if (Test-ChocolateyInstalled)', 'if ($false)'))" +call v-choco-refreshenv choco.exe %* \ No newline at end of file diff --git a/bin/cmake.cmd b/bin/cmake.cmd index 8b477aa..46f1286 100644 --- a/bin/cmake.cmd +++ b/bin/cmake.cmd @@ -1,2 +1,4 @@ @echo off -call "%VID_HOME%\tools\cmakew.bat" %* +where cmake.exe >nul 2>nul +if errorlevel 1 call choco install cmake -y & call %~dp0\v-choco-refreshenv +cmake.exe %* \ No newline at end of file diff --git a/bin/edit.cmd b/bin/edit.cmd index e551964..a22c8e6 100644 --- a/bin/edit.cmd +++ b/bin/edit.cmd @@ -1,4 +1,6 @@ @echo off setlocal for /D %%A in (. %1) do set open=%%~dpnA -start "" cmd /c "chcp 65001 & %VID_HOME%\tools\lite\lite.exe %open%" +where lite-xl.exe 2>nul >nul +if errorlevel 1 (call choco install -y lite-xl & call v-choco-refreshenv) +start "" cmd /c "chcp 65001 & lite-xl.exe %open%" diff --git a/start.cmd b/start.cmd index f5b9784..9e91c96 100644 --- a/start.cmd +++ b/start.cmd @@ -1,2 +1,5 @@ @echo off -cmd /k %~dp0\env.cmd +set VID_HOME=%~dp0 +set PATH=%~dp0\bin;%PATH% +echo %PATH% +cmd /k diff --git a/tools/cmakew.bat b/tools/cmakew.bat deleted file mode 100644 index c6beb7e..0000000 --- a/tools/cmakew.bat +++ /dev/null @@ -1,99 +0,0 @@ -@echo off -setlocal ENABLEEXTENSIONS -setlocal enableDelayedExpansion - -@rem set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set "CMAKE_VERSION=3.13.0" - -@rem extract semantic version codes -for /f "tokens=1,2,3 delims=." %%a in ("%CMAKE_VERSION%") do set CMAKE_VERSION_MAJOR=%%a&set CMAKE_VERSION_MINOR=%%b&set CMAKE_VERSION_PATCH=%%c - -@rem get script directory name -set DIRNAME=%~dp0\..\.cache -if "%DIRNAME%" == "" set DIRNAME=. - -@rem strip trailing backslash from DIRNAME path to make it easier to work with -IF %DIRNAME:~-1%==\ SET DIRNAME=%DIRNAME:~0,-1% - -@rem get OS bitness -reg Query "HKLM\Hardware\Description\System\CentralProcessor\0" | find /i "x86" > NUL && set OS_BITNESS=32BIT || set OS_BITNESS=64BIT - -set UNZIP_EXE=%DIRNAME%\7zip\7z.exe - -@rem require 7zip to unzip the cmake dist because windows sucks -if not exist %UNZIP_EXE% ( - echo Downloading 7zip... - - if %OS_BITNESS%==64BIT ( - call :downloadFile https://www.7-zip.org/a/7z1801-x64.exe %TEMP%\7zInstall.exe - ) else ( - call :downloadFile https://www.7-zip.org/a/7z1801.exe %TEMP%\7zInstall.exe - ) - - echo Installing 7zip - - @rem don't forget the trailing backslash here because 7zip is too stupid to deal with paths and just removes the last char - %TEMP%\7zInstall.exe /S /D=%DIRNAME%\7zip\ - del %TEMP%\7zInstall.exe -) - -set CMAKE_DIR=%DIRNAME%\cmake-%CMAKE_VERSION% -set CMAKE_ZIP=%TEMP%\cmake-%CMAKE_VERSION%.zip -set CMAKE_EXE=%CMAKE_DIR%\bin\cmake.exe - -@rem require correct cmake version -if not exist %CMAKE_EXE% ( - echo Downloading cmake version %CMAKE_VERSION%... - - if %OS_BITNESS%==64BIT ( - call :downloadFile https://cmake.org/files/v%CMAKE_VERSION_MAJOR%.%CMAKE_VERSION_MINOR%/cmake-%CMAKE_VERSION%-win64-x64.zip %CMAKE_ZIP% - ) else ( - call :downloadFile https://cmake.org/files/v%CMAKE_VERSION_MAJOR%.%CMAKE_VERSION_MINOR%/cmake-%CMAKE_VERSION%-win32-x86.zip %CMAKE_ZIP% - ) - - echo Installing cmake - - %UNZIP_EXE% x %CMAKE_ZIP% -o%DIRNAME% -y - del %CMAKE_ZIP% - - if %OS_BITNESS%==64BIT ( - ren %DIRNAME%\cmake-%CMAKE_VERSION%-win64-x64 cmake-%CMAKE_VERSION% - ) else ( - ren %DIRNAME%\cmake-%CMAKE_VERSION%-win32-x86 cmake-%CMAKE_VERSION% - ) -) - -@rem parse cli args to pass them to cmWake - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto runCmake - -set CMD_LINE_ARGS=%* -goto runCmake - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:runCmake -%CMAKE_EXE% %CMD_LINE_ARGS% -goto end - - -@rem args: fileUrl, filePath -:downloadFile -powershell -Command "(New-Object Net.WebClient).DownloadFile('%~1', '%~2')" -EXIT /B 0 - -:end -if "%OS%"=="Windows_NT" endlocal \ No newline at end of file diff --git a/tools/lite/SDL2.dll b/tools/lite/SDL2.dll deleted file mode 100644 index 7c546bc..0000000 Binary files a/tools/lite/SDL2.dll and /dev/null differ diff --git a/tools/lite/data/core/command.lua b/tools/lite/data/core/command.lua deleted file mode 100644 index 5164a13..0000000 --- a/tools/lite/data/core/command.lua +++ /dev/null @@ -1,69 +0,0 @@ -local core = require "core" -local command = {} - -command.map = {} - -local always_true = function() return true end - - -function command.add(predicate, map) - predicate = predicate or always_true - if type(predicate) == "string" then - predicate = require(predicate) - end - if type(predicate) == "table" then - local class = predicate - predicate = function() return core.active_view:is(class) end - end - for name, fn in pairs(map) do - assert(not command.map[name], "command already exists: " .. name) - command.map[name] = { predicate = predicate, perform = fn } - end -end - - -local function capitalize_first(str) - return str:sub(1, 1):upper() .. str:sub(2) -end - -function command.prettify_name(name) - return name:gsub(":", ": "):gsub("-", " "):gsub("%S+", capitalize_first) -end - - -function command.get_all_valid() - local res = {} - for name, cmd in pairs(command.map) do - if cmd.predicate() then - table.insert(res, name) - end - end - return res -end - - -local function perform(name) - local cmd = command.map[name] - if cmd and cmd.predicate() then - cmd.perform() - return true - end - return false -end - - -function command.perform(...) - local ok, res = core.try(perform, ...) - return not ok or res -end - - -function command.add_defaults() - local reg = { "core", "root", "command", "doc", "findreplace" } - for _, name in ipairs(reg) do - require("core.commands." .. name) - end -end - - -return command diff --git a/tools/lite/data/core/commands/command.lua b/tools/lite/data/core/commands/command.lua deleted file mode 100644 index f0b8007..0000000 --- a/tools/lite/data/core/commands/command.lua +++ /dev/null @@ -1,30 +0,0 @@ -local core = require "core" -local command = require "core.command" -local CommandView = require "core.commandview" - -local function has_commandview() - return core.active_view:is(CommandView) -end - - -command.add(has_commandview, { - ["command:submit"] = function() - core.active_view:submit() - end, - - ["command:complete"] = function() - core.active_view:complete() - end, - - ["command:escape"] = function() - core.active_view:exit() - end, - - ["command:select-previous"] = function() - core.active_view:move_suggestion_idx(1) - end, - - ["command:select-next"] = function() - core.active_view:move_suggestion_idx(-1) - end, -}) diff --git a/tools/lite/data/core/commands/core.lua b/tools/lite/data/core/commands/core.lua deleted file mode 100644 index dbe08a4..0000000 --- a/tools/lite/data/core/commands/core.lua +++ /dev/null @@ -1,101 +0,0 @@ -local core = require "core" -local common = require "core.common" -local command = require "core.command" -local keymap = require "core.keymap" -local LogView = require "core.logview" - - -local fullscreen = false - -command.add(nil, { - ["core:quit"] = function() - core.quit() - end, - - ["core:force-quit"] = function() - core.quit(true) - end, - - ["core:toggle-fullscreen"] = function() - fullscreen = not fullscreen - system.set_window_mode(fullscreen and "fullscreen" or "normal") - end, - - ["core:reload-module"] = function() - core.command_view:enter("Reload Module", function(text, item) - local text = item and item.text or text - core.reload_module(text) - core.log("Reloaded module %q", text) - end, function(text) - local items = {} - for name in pairs(package.loaded) do - table.insert(items, name) - end - return common.fuzzy_match(items, text) - end) - end, - - ["core:find-command"] = function() - local commands = command.get_all_valid() - core.command_view:enter("Do Command", function(text, item) - if item then - command.perform(item.command) - end - end, function(text) - local res = common.fuzzy_match(commands, text) - for i, name in ipairs(res) do - res[i] = { - text = command.prettify_name(name), - info = keymap.get_binding(name), - command = name, - } - end - return res - end) - end, - - ["core:find-file"] = function() - core.command_view:enter("Open File From Project", function(text, item) - text = item and item.text or text - core.root_view:open_doc(core.open_doc(text)) - end, function(text) - local files = {} - for _, item in pairs(core.project_files) do - if item.type == "file" then - table.insert(files, item.filename) - end - end - return common.fuzzy_match(files, text) - end) - end, - - ["core:new-doc"] = function() - core.root_view:open_doc(core.open_doc()) - end, - - ["core:open-file"] = function() - core.command_view:enter("Open File", function(text) - core.root_view:open_doc(core.open_doc(text)) - end, common.path_suggest) - end, - - ["core:open-log"] = function() - local node = core.root_view:get_active_node() - node:add_view(LogView()) - end, - - ["core:open-user-module"] = function() - core.root_view:open_doc(core.open_doc(EXEDIR .. "/data/user/init.lua")) - end, - - ["core:open-project-module"] = function() - local filename = ".lite_project.lua" - if system.get_file_info(filename) then - core.root_view:open_doc(core.open_doc(filename)) - else - local doc = core.open_doc() - core.root_view:open_doc(doc) - doc:save(filename) - end - end, -}) diff --git a/tools/lite/data/core/commands/doc.lua b/tools/lite/data/core/commands/doc.lua deleted file mode 100644 index 1afd546..0000000 --- a/tools/lite/data/core/commands/doc.lua +++ /dev/null @@ -1,363 +0,0 @@ -local core = require "core" -local command = require "core.command" -local common = require "core.common" -local config = require "core.config" -local translate = require "core.doc.translate" -local DocView = require "core.docview" - - -local function dv() - return core.active_view -end - - -local function doc() - return core.active_view.doc -end - - -local function get_indent_string() - if config.tab_type == "hard" then - return "\t" - end - return string.rep(" ", config.indent_size) -end - - -local function insert_at_start_of_selected_lines(text, skip_empty) - local line1, col1, line2, col2, swap = doc():get_selection(true) - for line = line1, line2 do - local line_text = doc().lines[line] - if (not skip_empty or line_text:find("%S")) then - doc():insert(line, 1, text) - end - end - doc():set_selection(line1, col1 + #text, line2, col2 + #text, swap) -end - - -local function remove_from_start_of_selected_lines(text, skip_empty) - local line1, col1, line2, col2, swap = doc():get_selection(true) - for line = line1, line2 do - local line_text = doc().lines[line] - if line_text:sub(1, #text) == text - and (not skip_empty or line_text:find("%S")) - then - doc():remove(line, 1, line, #text + 1) - end - end - doc():set_selection(line1, col1 - #text, line2, col2 - #text, swap) -end - - -local function append_line_if_last_line(line) - if line >= #doc().lines then - doc():insert(line, math.huge, "\n") - end -end - - -local function save(filename) - doc():save(filename) - core.log("Saved \"%s\"", doc().filename) -end - - -local commands = { - ["doc:undo"] = function() - doc():undo() - end, - - ["doc:redo"] = function() - doc():redo() - end, - - ["doc:cut"] = function() - if doc():has_selection() then - local text = doc():get_text(doc():get_selection()) - system.set_clipboard(text) - doc():delete_to(0) - end - end, - - ["doc:copy"] = function() - if doc():has_selection() then - local text = doc():get_text(doc():get_selection()) - system.set_clipboard(text) - end - end, - - ["doc:paste"] = function() - doc():text_input(system.get_clipboard():gsub("\r", "")) - end, - - ["doc:newline"] = function() - local line, col = doc():get_selection() - local indent = doc().lines[line]:match("^[\t ]*") - if col <= #indent then - indent = indent:sub(#indent + 2 - col) - end - doc():text_input("\n" .. indent) - end, - - ["doc:newline-below"] = function() - local line = doc():get_selection() - local indent = doc().lines[line]:match("^[\t ]*") - doc():insert(line, math.huge, "\n" .. indent) - doc():set_selection(line + 1, math.huge) - end, - - ["doc:newline-above"] = function() - local line = doc():get_selection() - local indent = doc().lines[line]:match("^[\t ]*") - doc():insert(line, 1, indent .. "\n") - doc():set_selection(line, math.huge) - end, - - ["doc:delete"] = function() - local line, col = doc():get_selection() - if not doc():has_selection() and doc().lines[line]:find("^%s*$", col) then - doc():remove(line, col, line, math.huge) - end - doc():delete_to(translate.next_char) - end, - - ["doc:backspace"] = function() - local line, col = doc():get_selection() - if not doc():has_selection() then - local text = doc():get_text(line, 1, line, col) - if #text >= config.indent_size and text:find("^ *$") then - doc():delete_to(0, -config.indent_size) - return - end - end - doc():delete_to(translate.previous_char) - end, - - ["doc:select-all"] = function() - doc():set_selection(1, 1, math.huge, math.huge) - end, - - ["doc:select-none"] = function() - local line, col = doc():get_selection() - doc():set_selection(line, col) - end, - - ["doc:select-lines"] = function() - local line1, _, line2, _, swap = doc():get_selection(true) - append_line_if_last_line(line2) - doc():set_selection(line1, 1, line2 + 1, 1, swap) - end, - - ["doc:select-word"] = function() - local line1, col1 = doc():get_selection(true) - local line1, col1 = translate.start_of_word(doc(), line1, col1) - local line2, col2 = translate.end_of_word(doc(), line1, col1) - doc():set_selection(line2, col2, line1, col1) - end, - - ["doc:join-lines"] = function() - local line1, _, line2 = doc():get_selection(true) - if line1 == line2 then line2 = line2 + 1 end - local text = doc():get_text(line1, 1, line2, math.huge) - text = text:gsub("\n[\t ]*", " ") - doc():insert(line1, 1, text) - doc():remove(line1, #text + 1, line2, math.huge) - if doc():has_selection() then - doc():set_selection(line1, math.huge) - end - end, - - ["doc:indent"] = function() - local text = get_indent_string() - if doc():has_selection() then - insert_at_start_of_selected_lines(text) - else - doc():text_input(text) - end - end, - - ["doc:unindent"] = function() - local text = get_indent_string() - remove_from_start_of_selected_lines(text) - end, - - ["doc:duplicate-lines"] = function() - local line1, col1, line2, col2, swap = doc():get_selection(true) - append_line_if_last_line(line2) - local text = doc():get_text(line1, 1, line2 + 1, 1) - doc():insert(line2 + 1, 1, text) - local n = line2 - line1 + 1 - doc():set_selection(line1 + n, col1, line2 + n, col2, swap) - end, - - ["doc:delete-lines"] = function() - local line1, col1, line2 = doc():get_selection(true) - append_line_if_last_line(line2) - doc():remove(line1, 1, line2 + 1, 1) - doc():set_selection(line1, col1) - end, - - ["doc:move-lines-up"] = function() - local line1, col1, line2, col2, swap = doc():get_selection(true) - append_line_if_last_line(line2) - if line1 > 1 then - local text = doc().lines[line1 - 1] - doc():insert(line2 + 1, 1, text) - doc():remove(line1 - 1, 1, line1, 1) - doc():set_selection(line1 - 1, col1, line2 - 1, col2, swap) - end - end, - - ["doc:move-lines-down"] = function() - local line1, col1, line2, col2, swap = doc():get_selection(true) - append_line_if_last_line(line2 + 1) - if line2 < #doc().lines then - local text = doc().lines[line2 + 1] - doc():remove(line2 + 1, 1, line2 + 2, 1) - doc():insert(line1, 1, text) - doc():set_selection(line1 + 1, col1, line2 + 1, col2, swap) - end - end, - - ["doc:toggle-line-comments"] = function() - local comment = doc().syntax.comment - if not comment then return end - local comment_text = comment .. " " - local line1, _, line2 = doc():get_selection(true) - local uncomment = true - for line = line1, line2 do - local text = doc().lines[line] - if text:find("%S") and text:find(comment_text, 1, true) ~= 1 then - uncomment = false - end - end - if uncomment then - remove_from_start_of_selected_lines(comment_text, true) - else - insert_at_start_of_selected_lines(comment_text, true) - end - end, - - ["doc:upper-case"] = function() - doc():replace(string.upper) - end, - - ["doc:lower-case"] = function() - doc():replace(string.lower) - end, - - ["doc:go-to-line"] = function() - local dv = dv() - - local items - local function init_items() - if items then return end - items = {} - local mt = { __tostring = function(x) return x.text end } - for i, line in ipairs(dv.doc.lines) do - local item = { text = line:sub(1, -2), line = i, info = "line: " .. i } - table.insert(items, setmetatable(item, mt)) - end - end - - core.command_view:enter("Go To Line", function(text, item) - local line = item and item.line or tonumber(text) - if not line then - core.error("Invalid line number or unmatched string") - return - end - dv.doc:set_selection(line, 1 ) - dv:scroll_to_line(line, true) - - end, function(text) - if not text:find("^%d*$") then - init_items() - return common.fuzzy_match(items, text) - end - end) - end, - - ["doc:toggle-line-ending"] = function() - doc().crlf = not doc().crlf - end, - - ["doc:save-as"] = function() - if doc().filename then - core.command_view:set_text(doc().filename) - end - core.command_view:enter("Save As", function(filename) - save(filename) - end, common.path_suggest) - end, - - ["doc:save"] = function() - if doc().filename then - save() - else - command.perform("doc:save-as") - end - end, - - ["doc:rename"] = function() - local old_filename = doc().filename - if not old_filename then - core.error("Cannot rename unsaved doc") - return - end - core.command_view:set_text(old_filename) - core.command_view:enter("Rename", function(filename) - doc():save(filename) - core.log("Renamed \"%s\" to \"%s\"", old_filename, filename) - if filename ~= old_filename then - os.remove(old_filename) - end - end, common.path_suggest) - end, -} - - -local translations = { - ["previous-char"] = translate.previous_char, - ["next-char"] = translate.next_char, - ["previous-word-start"] = translate.previous_word_start, - ["next-word-end"] = translate.next_word_end, - ["previous-block-start"] = translate.previous_block_start, - ["next-block-end"] = translate.next_block_end, - ["start-of-doc"] = translate.start_of_doc, - ["end-of-doc"] = translate.end_of_doc, - ["start-of-line"] = translate.start_of_line, - ["end-of-line"] = translate.end_of_line, - ["start-of-word"] = translate.start_of_word, - ["end-of-word"] = translate.end_of_word, - ["previous-line"] = DocView.translate.previous_line, - ["next-line"] = DocView.translate.next_line, - ["previous-page"] = DocView.translate.previous_page, - ["next-page"] = DocView.translate.next_page, -} - -for name, fn in pairs(translations) do - commands["doc:move-to-" .. name] = function() doc():move_to(fn, dv()) end - commands["doc:select-to-" .. name] = function() doc():select_to(fn, dv()) end - commands["doc:delete-to-" .. name] = function() doc():delete_to(fn, dv()) end -end - -commands["doc:move-to-previous-char"] = function() - if doc():has_selection() then - local line, col = doc():get_selection(true) - doc():set_selection(line, col) - else - doc():move_to(translate.previous_char) - end -end - -commands["doc:move-to-next-char"] = function() - if doc():has_selection() then - local _, _, line, col = doc():get_selection(true) - doc():set_selection(line, col) - else - doc():move_to(translate.next_char) - end -end - -command.add("core.docview", commands) diff --git a/tools/lite/data/core/commands/findreplace.lua b/tools/lite/data/core/commands/findreplace.lua deleted file mode 100644 index 937c410..0000000 --- a/tools/lite/data/core/commands/findreplace.lua +++ /dev/null @@ -1,170 +0,0 @@ -local core = require "core" -local command = require "core.command" -local config = require "core.config" -local search = require "core.doc.search" -local DocView = require "core.docview" - -local max_previous_finds = 50 - - -local function doc() - return core.active_view.doc -end - - -local previous_finds -local last_doc -local last_fn, last_text - - -local function push_previous_find(doc, sel) - if last_doc ~= doc then - last_doc = doc - previous_finds = {} - end - if #previous_finds >= max_previous_finds then - table.remove(previous_finds, 1) - end - table.insert(previous_finds, sel or { doc:get_selection() }) -end - - -local function find(label, search_fn) - local dv = core.active_view - local sel = { dv.doc:get_selection() } - local text = dv.doc:get_text(table.unpack(sel)) - local found = false - - core.command_view:set_text(text, true) - - core.command_view:enter(label, function(text) - if found then - last_fn, last_text = search_fn, text - previous_finds = {} - push_previous_find(dv.doc, sel) - else - core.error("Couldn't find %q", text) - dv.doc:set_selection(table.unpack(sel)) - dv:scroll_to_make_visible(sel[1], sel[2]) - end - - end, function(text) - local ok, line1, col1, line2, col2 = pcall(search_fn, dv.doc, sel[1], sel[2], text) - if ok and line1 and text ~= "" then - dv.doc:set_selection(line2, col2, line1, col1) - dv:scroll_to_line(line2, true) - found = true - else - dv.doc:set_selection(table.unpack(sel)) - found = false - end - - end, function(explicit) - if explicit then - dv.doc:set_selection(table.unpack(sel)) - dv:scroll_to_make_visible(sel[1], sel[2]) - end - end) -end - - -local function replace(kind, default, fn) - core.command_view:set_text(default, true) - - core.command_view:enter("Find To Replace " .. kind, function(old) - core.command_view:set_text(old, true) - - local s = string.format("Replace %s %q With", kind, old) - core.command_view:enter(s, function(new) - local n = doc():replace(function(text) - return fn(text, old, new) - end) - core.log("Replaced %d instance(s) of %s %q with %q", n, kind, old, new) - end) - end) -end - - -local function has_selection() - return core.active_view:is(DocView) - and core.active_view.doc:has_selection() -end - -command.add(has_selection, { - ["find-replace:select-next"] = function() - local l1, c1, l2, c2 = doc():get_selection(true) - local text = doc():get_text(l1, c1, l2, c2) - local l1, c1, l2, c2 = search.find(doc(), l2, c2, text, { wrap = true }) - if l2 then doc():set_selection(l2, c2, l1, c1) end - end -}) - -command.add("core.docview", { - ["find-replace:find"] = function() - find("Find Text", function(doc, line, col, text) - local opt = { wrap = true, no_case = true } - return search.find(doc, line, col, text, opt) - end) - end, - - ["find-replace:find-pattern"] = function() - find("Find Text Pattern", function(doc, line, col, text) - local opt = { wrap = true, no_case = true, pattern = true } - return search.find(doc, line, col, text, opt) - end) - end, - - ["find-replace:repeat-find"] = function() - if not last_fn then - core.error("No find to continue from") - else - local line, col = doc():get_selection() - local line1, col1, line2, col2 = last_fn(doc(), line, col, last_text) - if line1 then - push_previous_find(doc()) - doc():set_selection(line2, col2, line1, col1) - core.active_view:scroll_to_line(line2, true) - end - end - end, - - ["find-replace:previous-find"] = function() - local sel = table.remove(previous_finds) - if not sel or doc() ~= last_doc then - core.error("No previous finds") - return - end - doc():set_selection(table.unpack(sel)) - core.active_view:scroll_to_line(sel[3], true) - end, - - ["find-replace:replace"] = function() - replace("Text", "", function(text, old, new) - return text:gsub(old:gsub("%W", "%%%1"), new:gsub("%%", "%%%%"), nil) - end) - end, - - ["find-replace:replace-pattern"] = function() - replace("Pattern", "", function(text, old, new) - return text:gsub(old, new) - end) - end, - - ["find-replace:replace-symbol"] = function() - local first = "" - if doc():has_selection() then - local text = doc():get_text(doc():get_selection()) - first = text:match(config.symbol_pattern) or "" - end - replace("Symbol", first, function(text, old, new) - local n = 0 - local res = text:gsub(config.symbol_pattern, function(sym) - if old == sym then - n = n + 1 - return new - end - end) - return res, n - end) - end, -}) diff --git a/tools/lite/data/core/commands/root.lua b/tools/lite/data/core/commands/root.lua deleted file mode 100644 index 58c83e2..0000000 --- a/tools/lite/data/core/commands/root.lua +++ /dev/null @@ -1,105 +0,0 @@ -local core = require "core" -local style = require "core.style" -local DocView = require "core.docview" -local command = require "core.command" -local common = require "core.common" - - -local t = { - ["root:close"] = function() - local node = core.root_view:get_active_node() - node:close_active_view(core.root_view.root_node) - end, - - ["root:switch-to-previous-tab"] = function() - local node = core.root_view:get_active_node() - local idx = node:get_view_idx(core.active_view) - idx = idx - 1 - if idx < 1 then idx = #node.views end - node:set_active_view(node.views[idx]) - end, - - ["root:switch-to-next-tab"] = function() - local node = core.root_view:get_active_node() - local idx = node:get_view_idx(core.active_view) - idx = idx + 1 - if idx > #node.views then idx = 1 end - node:set_active_view(node.views[idx]) - end, - - ["root:move-tab-left"] = function() - local node = core.root_view:get_active_node() - local idx = node:get_view_idx(core.active_view) - if idx > 1 then - table.remove(node.views, idx) - table.insert(node.views, idx - 1, core.active_view) - end - end, - - ["root:move-tab-right"] = function() - local node = core.root_view:get_active_node() - local idx = node:get_view_idx(core.active_view) - if idx < #node.views then - table.remove(node.views, idx) - table.insert(node.views, idx + 1, core.active_view) - end - end, - - ["root:shrink"] = function() - local node = core.root_view:get_active_node() - local parent = node:get_parent_node(core.root_view.root_node) - local n = (parent.a == node) and -0.1 or 0.1 - parent.divider = common.clamp(parent.divider + n, 0.1, 0.9) - end, - - ["root:grow"] = function() - local node = core.root_view:get_active_node() - local parent = node:get_parent_node(core.root_view.root_node) - local n = (parent.a == node) and 0.1 or -0.1 - parent.divider = common.clamp(parent.divider + n, 0.1, 0.9) - end, -} - - -for i = 1, 9 do - t["root:switch-to-tab-" .. i] = function() - local node = core.root_view:get_active_node() - local view = node.views[i] - if view then - node:set_active_view(view) - end - end -end - - -for _, dir in ipairs { "left", "right", "up", "down" } do - t["root:split-" .. dir] = function() - local node = core.root_view:get_active_node() - local av = node.active_view - node:split(dir) - if av:is(DocView) then - core.root_view:open_doc(av.doc) - end - end - - t["root:switch-to-" .. dir] = function() - local node = core.root_view:get_active_node() - local x, y - if dir == "left" or dir == "right" then - y = node.position.y + node.size.y / 2 - x = node.position.x + (dir == "left" and -1 or node.size.x + style.divider_size) - else - x = node.position.x + node.size.x / 2 - y = node.position.y + (dir == "up" and -1 or node.size.y + style.divider_size) - end - local node = core.root_view.root_node:get_child_overlapping_point(x, y) - if not node:get_locked_size() then - core.set_active_view(node.active_view) - end - end -end - -command.add(function() - local node = core.root_view:get_active_node() - return not node:get_locked_size() -end, t) diff --git a/tools/lite/data/core/commandview.lua b/tools/lite/data/core/commandview.lua deleted file mode 100644 index 3fbb1ff..0000000 --- a/tools/lite/data/core/commandview.lua +++ /dev/null @@ -1,256 +0,0 @@ -local core = require "core" -local common = require "core.common" -local style = require "core.style" -local Doc = require "core.doc" -local DocView = require "core.docview" -local View = require "core.view" - - -local SingleLineDoc = Doc:extend() - -function SingleLineDoc:insert(line, col, text) - SingleLineDoc.super.insert(self, line, col, text:gsub("\n", "")) -end - - -local CommandView = DocView:extend() - -local max_suggestions = 10 - -local noop = function() end - -local default_state = { - submit = noop, - suggest = noop, - cancel = noop, -} - - -function CommandView:new() - CommandView.super.new(self, SingleLineDoc()) - self.suggestion_idx = 1 - self.suggestions = {} - self.suggestions_height = 0 - self.last_change_id = 0 - self.gutter_width = 0 - self.gutter_text_brightness = 0 - self.selection_offset = 0 - self.state = default_state - self.font = "font" - self.size.y = 0 - self.label = "" -end - - -function CommandView:get_name() - return View.get_name(self) -end - - -function CommandView:get_line_screen_position() - local x = CommandView.super.get_line_screen_position(self, 1) - local _, y = self:get_content_offset() - local lh = self:get_line_height() - return x, y + (self.size.y - lh) / 2 -end - - -function CommandView:get_scrollable_size() - return 0 -end - - -function CommandView:scroll_to_make_visible() - -- no-op function to disable this functionality -end - - -function CommandView:get_text() - return self.doc:get_text(1, 1, 1, math.huge) -end - - -function CommandView:set_text(text, select) - self.doc:remove(1, 1, math.huge, math.huge) - self.doc:text_input(text) - if select then - self.doc:set_selection(math.huge, math.huge, 1, 1) - end -end - - -function CommandView:move_suggestion_idx(dir) - local n = self.suggestion_idx + dir - self.suggestion_idx = common.clamp(n, 1, #self.suggestions) - self:complete() - self.last_change_id = self.doc:get_change_id() -end - - -function CommandView:complete() - if #self.suggestions > 0 then - self:set_text(self.suggestions[self.suggestion_idx].text) - end -end - - -function CommandView:submit() - local suggestion = self.suggestions[self.suggestion_idx] - local text = self:get_text() - local submit = self.state.submit - self:exit(true) - submit(text, suggestion) -end - - -function CommandView:enter(text, submit, suggest, cancel) - if self.state ~= default_state then - return - end - self.state = { - submit = submit or noop, - suggest = suggest or noop, - cancel = cancel or noop, - } - core.set_active_view(self) - self:update_suggestions() - self.gutter_text_brightness = 100 - self.label = text .. ": " -end - - -function CommandView:exit(submitted, inexplicit) - if core.active_view == self then - core.set_active_view(core.last_active_view) - end - local cancel = self.state.cancel - self.state = default_state - self.doc:reset() - self.suggestions = {} - if not submitted then cancel(not inexplicit) end -end - - -function CommandView:get_gutter_width() - return self.gutter_width -end - - -function CommandView:get_suggestion_line_height() - return self:get_font():get_height() + style.padding.y -end - - -function CommandView:update_suggestions() - local t = self.state.suggest(self:get_text()) or {} - local res = {} - for i, item in ipairs(t) do - if i == max_suggestions then - break - end - if type(item) == "string" then - item = { text = item } - end - res[i] = item - end - self.suggestions = res - self.suggestion_idx = 1 -end - - -function CommandView:update() - CommandView.super.update(self) - - if core.active_view ~= self and self.state ~= default_state then - self:exit(false, true) - end - - -- update suggestions if text has changed - if self.last_change_id ~= self.doc:get_change_id() then - self:update_suggestions() - self.last_change_id = self.doc:get_change_id() - end - - -- update gutter text color brightness - self:move_towards("gutter_text_brightness", 0, 0.1) - - -- update gutter width - local dest = self:get_font():get_width(self.label) + style.padding.x - if self.size.y <= 0 then - self.gutter_width = dest - else - self:move_towards("gutter_width", dest) - end - - -- update suggestions box height - local lh = self:get_suggestion_line_height() - local dest = #self.suggestions * lh - self:move_towards("suggestions_height", dest) - - -- update suggestion cursor offset - local dest = self.suggestion_idx * self:get_suggestion_line_height() - self:move_towards("selection_offset", dest) - - -- update size based on whether this is the active_view - local dest = 0 - if self == core.active_view then - dest = style.font:get_height() + style.padding.y * 2 - end - self:move_towards(self.size, "y", dest) -end - - -function CommandView:draw_line_highlight() - -- no-op function to disable this functionality -end - - -function CommandView:draw_line_gutter(idx, x, y) - local yoffset = self:get_line_text_y_offset() - local pos = self.position - local color = common.lerp(style.text, style.accent, self.gutter_text_brightness / 100) - core.push_clip_rect(pos.x, pos.y, self:get_gutter_width(), self.size.y) - x = x + style.padding.x - renderer.draw_text(self:get_font(), self.label, x, y + yoffset, color) - core.pop_clip_rect() -end - - -local function draw_suggestions_box(self) - local lh = self:get_suggestion_line_height() - local dh = style.divider_size - local x, _ = self:get_line_screen_position() - local h = math.ceil(self.suggestions_height) - local rx, ry, rw, rh = self.position.x, self.position.y - h - dh, self.size.x, h - - -- draw suggestions background - if #self.suggestions > 0 then - renderer.draw_rect(rx, ry, rw, rh, style.background3) - renderer.draw_rect(rx, ry - dh, rw, dh, style.divider) - local y = self.position.y - self.selection_offset - dh - renderer.draw_rect(rx, y, rw, lh, style.line_highlight) - end - - -- draw suggestion text - core.push_clip_rect(rx, ry, rw, rh) - for i, item in ipairs(self.suggestions) do - local color = (i == self.suggestion_idx) and style.accent or style.text - local y = self.position.y - i * lh - dh - common.draw_text(self:get_font(), color, item.text, nil, x, y, 0, lh) - - if item.info then - local w = self.size.x - x - style.padding.x - common.draw_text(self:get_font(), style.dim, item.info, "right", x, y, w, lh) - end - end - core.pop_clip_rect() -end - - -function CommandView:draw() - CommandView.super.draw(self) - core.root_view:defer_draw(draw_suggestions_box, self) -end - - -return CommandView diff --git a/tools/lite/data/core/common.lua b/tools/lite/data/core/common.lua deleted file mode 100644 index 1fc91b8..0000000 --- a/tools/lite/data/core/common.lua +++ /dev/null @@ -1,140 +0,0 @@ -local common = {} - - -function common.is_utf8_cont(char) - local byte = char:byte() - return byte >= 0x80 and byte < 0xc0 -end - - -function common.utf8_chars(text) - return text:gmatch("[\0-\x7f\xc2-\xf4][\x80-\xbf]*") -end - - -function common.clamp(n, lo, hi) - return math.max(math.min(n, hi), lo) -end - - -function common.round(n) - return n >= 0 and math.floor(n + 0.5) or math.ceil(n - 0.5) -end - - -function common.lerp(a, b, t) - if type(a) ~= "table" then - return a + (b - a) * t - end - local res = {} - for k, v in pairs(b) do - res[k] = common.lerp(a[k], v, t) - end - return res -end - - -function common.color(str) - local r, g, b, a = str:match("#(%x%x)(%x%x)(%x%x)") - if r then - r = tonumber(r, 16) - g = tonumber(g, 16) - b = tonumber(b, 16) - a = 1 - elseif str:match("rgba?%s*%([%d%s%.,]+%)") then - local f = str:gmatch("[%d.]+") - r = (f() or 0) - g = (f() or 0) - b = (f() or 0) - a = f() or 1 - else - error(string.format("bad color string '%s'", str)) - end - return r, g, b, a * 0xff -end - - -local function compare_score(a, b) - return a.score > b.score -end - -local function fuzzy_match_items(items, needle) - local res = {} - for _, item in ipairs(items) do - local score = system.fuzzy_match(tostring(item), needle) - if score then - table.insert(res, { text = item, score = score }) - end - end - table.sort(res, compare_score) - for i, item in ipairs(res) do - res[i] = item.text - end - return res -end - - -function common.fuzzy_match(haystack, needle) - if type(haystack) == "table" then - return fuzzy_match_items(haystack, needle) - end - return system.fuzzy_match(haystack, needle) -end - - -function common.path_suggest(text) - local path, name = text:match("^(.-)([^/\\]*)$") - local files = system.list_dir(path == "" and "." or path) or {} - local res = {} - for _, file in ipairs(files) do - file = path .. file - local info = system.get_file_info(file) - if info then - if info.type == "dir" then - file = file .. PATHSEP - end - if file:lower():find(text:lower(), nil, true) == 1 then - table.insert(res, file) - end - end - end - return res -end - - -function common.match_pattern(text, pattern, ...) - if type(pattern) == "string" then - return text:find(pattern, ...) - end - for _, p in ipairs(pattern) do - local s, e = common.match_pattern(text, p, ...) - if s then return s, e end - end - return false -end - - -function common.draw_text(font, color, text, align, x,y,w,h) - local tw, th = font:get_width(text), font:get_height(text) - if align == "center" then - x = x + (w - tw) / 2 - elseif align == "right" then - x = x + (w - tw) - end - y = common.round(y + (h - th) / 2) - return renderer.draw_text(font, text, x, y, color), y + th -end - - -function common.bench(name, fn, ...) - local start = system.get_time() - local res = fn(...) - local t = system.get_time() - start - local ms = t * 1000 - local per = (t / (1 / 60)) * 100 - print(string.format("*** %-16s : %8.3fms %6.2f%%", name, ms, per)) - return res -end - - -return common diff --git a/tools/lite/data/core/config.lua b/tools/lite/data/core/config.lua deleted file mode 100644 index a9f106f..0000000 --- a/tools/lite/data/core/config.lua +++ /dev/null @@ -1,20 +0,0 @@ -local config = {} - -config.project_scan_rate = 5 -config.fps = 60 -config.max_log_items = 80 -config.message_timeout = 3 -config.mouse_wheel_scroll = 50 * SCALE -config.file_size_limit = 10 -config.ignore_files = "^%." -config.symbol_pattern = "[%a_][%w_]*" -config.non_word_chars = " \t\n/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-" -config.undo_merge_timeout = 0.3 -config.max_undos = 10000 -config.highlight_current_line = true -config.line_height = 1.2 -config.indent_size = 2 -config.tab_type = "soft" -config.line_limit = 80 - -return config diff --git a/tools/lite/data/core/doc/highlighter.lua b/tools/lite/data/core/doc/highlighter.lua deleted file mode 100644 index e7650d0..0000000 --- a/tools/lite/data/core/doc/highlighter.lua +++ /dev/null @@ -1,80 +0,0 @@ -local core = require "core" -local config = require "core.config" -local tokenizer = require "core.tokenizer" -local Object = require "core.object" - - -local Highlighter = Object:extend() - - -function Highlighter:new(doc) - self.doc = doc - self:reset() - - -- init incremental syntax highlighting - core.add_thread(function() - while true do - if self.first_invalid_line > self.max_wanted_line then - self.max_wanted_line = 0 - coroutine.yield(1 / config.fps) - - else - local max = math.min(self.first_invalid_line + 40, self.max_wanted_line) - - for i = self.first_invalid_line, max do - local state = (i > 1) and self.lines[i - 1].state - local line = self.lines[i] - if not (line and line.init_state == state) then - self.lines[i] = self:tokenize_line(i, state) - end - end - - self.first_invalid_line = max + 1 - core.redraw = true - coroutine.yield() - end - end - end, self) -end - - -function Highlighter:reset() - self.lines = {} - self.first_invalid_line = 1 - self.max_wanted_line = 0 -end - - -function Highlighter:invalidate(idx) - self.first_invalid_line = math.min(self.first_invalid_line, idx) - self.max_wanted_line = math.min(self.max_wanted_line, #self.doc.lines) -end - - -function Highlighter:tokenize_line(idx, state) - local res = {} - res.init_state = state - res.text = self.doc.lines[idx] - res.tokens, res.state = tokenizer.tokenize(self.doc.syntax, res.text, state) - return res -end - - -function Highlighter:get_line(idx) - local line = self.lines[idx] - if not line or line.text ~= self.doc.lines[idx] then - local prev = self.lines[idx - 1] - line = self:tokenize_line(idx, prev and prev.state) - self.lines[idx] = line - end - self.max_wanted_line = math.max(self.max_wanted_line, idx) - return line -end - - -function Highlighter:each_token(idx) - return tokenizer.each_token(self:get_line(idx).tokens) -end - - -return Highlighter diff --git a/tools/lite/data/core/doc/init.lua b/tools/lite/data/core/doc/init.lua deleted file mode 100644 index 83b5fc0..0000000 --- a/tools/lite/data/core/doc/init.lua +++ /dev/null @@ -1,393 +0,0 @@ -local Object = require "core.object" -local Highlighter = require "core.doc.highlighter" -local syntax = require "core.syntax" -local config = require "core.config" -local common = require "core.common" - - -local Doc = Object:extend() - - -local function split_lines(text) - local res = {} - for line in (text .. "\n"):gmatch("(.-)\n") do - table.insert(res, line) - end - return res -end - - -local function splice(t, at, remove, insert) - insert = insert or {} - local offset = #insert - remove - local old_len = #t - if offset < 0 then - for i = at - offset, old_len - offset do - t[i + offset] = t[i] - end - elseif offset > 0 then - for i = old_len, at, -1 do - t[i + offset] = t[i] - end - end - for i, item in ipairs(insert) do - t[at + i - 1] = item - end -end - - -function Doc:new(filename) - self:reset() - if filename then - self:load(filename) - end -end - - -function Doc:reset() - self.lines = { "\n" } - self.selection = { a = { line=1, col=1 }, b = { line=1, col=1 } } - self.undo_stack = { idx = 1 } - self.redo_stack = { idx = 1 } - self.clean_change_id = 1 - self.highlighter = Highlighter(self) - self:reset_syntax() -end - - -function Doc:reset_syntax() - local header = self:get_text(1, 1, self:position_offset(1, 1, 128)) - local syn = syntax.get(self.filename or "", header) - if self.syntax ~= syn then - self.syntax = syn - self.highlighter:reset() - end -end - - -function Doc:load(filename) - local fp = assert( io.open(filename, "rb") ) - self:reset() - self.filename = filename - self.lines = {} - for line in fp:lines() do - if line:byte(-1) == 13 then - line = line:sub(1, -2) - self.crlf = true - end - table.insert(self.lines, line .. "\n") - end - if #self.lines == 0 then - table.insert(self.lines, "\n") - end - fp:close() - self:reset_syntax() -end - - -function Doc:save(filename) - filename = filename or assert(self.filename, "no filename set to default to") - local fp = assert( io.open(filename, "wb") ) - for _, line in ipairs(self.lines) do - if self.crlf then line = line:gsub("\n", "\r\n") end - fp:write(line) - end - fp:close() - self.filename = filename or self.filename - self:reset_syntax() - self:clean() -end - - -function Doc:get_name() - return self.filename or "unsaved" -end - - -function Doc:is_dirty() - return self.clean_change_id ~= self:get_change_id() -end - - -function Doc:clean() - self.clean_change_id = self:get_change_id() -end - - -function Doc:get_change_id() - return self.undo_stack.idx -end - - -function Doc:set_selection(line1, col1, line2, col2, swap) - assert(not line2 == not col2, "expected 2 or 4 arguments") - if swap then line1, col1, line2, col2 = line2, col2, line1, col1 end - line1, col1 = self:sanitize_position(line1, col1) - line2, col2 = self:sanitize_position(line2 or line1, col2 or col1) - self.selection.a.line, self.selection.a.col = line1, col1 - self.selection.b.line, self.selection.b.col = line2, col2 -end - - -local function sort_positions(line1, col1, line2, col2) - if line1 > line2 - or line1 == line2 and col1 > col2 then - return line2, col2, line1, col1, true - end - return line1, col1, line2, col2, false -end - - -function Doc:get_selection(sort) - local a, b = self.selection.a, self.selection.b - if sort then - return sort_positions(a.line, a.col, b.line, b.col) - end - return a.line, a.col, b.line, b.col -end - - -function Doc:has_selection() - local a, b = self.selection.a, self.selection.b - return not (a.line == b.line and a.col == b.col) -end - - -function Doc:sanitize_selection() - self:set_selection(self:get_selection()) -end - - -function Doc:sanitize_position(line, col) - line = common.clamp(line, 1, #self.lines) - col = common.clamp(col, 1, #self.lines[line]) - return line, col -end - - -local function position_offset_func(self, line, col, fn, ...) - line, col = self:sanitize_position(line, col) - return fn(self, line, col, ...) -end - - -local function position_offset_byte(self, line, col, offset) - line, col = self:sanitize_position(line, col) - col = col + offset - while line > 1 and col < 1 do - line = line - 1 - col = col + #self.lines[line] - end - while line < #self.lines and col > #self.lines[line] do - col = col - #self.lines[line] - line = line + 1 - end - return self:sanitize_position(line, col) -end - - -local function position_offset_linecol(self, line, col, lineoffset, coloffset) - return self:sanitize_position(line + lineoffset, col + coloffset) -end - - -function Doc:position_offset(line, col, ...) - if type(...) ~= "number" then - return position_offset_func(self, line, col, ...) - elseif select("#", ...) == 1 then - return position_offset_byte(self, line, col, ...) - elseif select("#", ...) == 2 then - return position_offset_linecol(self, line, col, ...) - else - error("bad number of arguments") - end -end - - -function Doc:get_text(line1, col1, line2, col2) - line1, col1 = self:sanitize_position(line1, col1) - line2, col2 = self:sanitize_position(line2, col2) - line1, col1, line2, col2 = sort_positions(line1, col1, line2, col2) - if line1 == line2 then - return self.lines[line1]:sub(col1, col2 - 1) - end - local lines = { self.lines[line1]:sub(col1) } - for i = line1 + 1, line2 - 1 do - table.insert(lines, self.lines[i]) - end - table.insert(lines, self.lines[line2]:sub(1, col2 - 1)) - return table.concat(lines) -end - - -function Doc:get_char(line, col) - line, col = self:sanitize_position(line, col) - return self.lines[line]:sub(col, col) -end - - -local function push_undo(undo_stack, time, type, ...) - undo_stack[undo_stack.idx] = { type = type, time = time, ... } - undo_stack[undo_stack.idx - config.max_undos] = nil - undo_stack.idx = undo_stack.idx + 1 -end - - -local function pop_undo(self, undo_stack, redo_stack) - -- pop command - local cmd = undo_stack[undo_stack.idx - 1] - if not cmd then return end - undo_stack.idx = undo_stack.idx - 1 - - -- handle command - if cmd.type == "insert" then - local line, col, text = table.unpack(cmd) - self:raw_insert(line, col, text, redo_stack, cmd.time) - - elseif cmd.type == "remove" then - local line1, col1, line2, col2 = table.unpack(cmd) - self:raw_remove(line1, col1, line2, col2, redo_stack, cmd.time) - - elseif cmd.type == "selection" then - self.selection.a.line, self.selection.a.col = cmd[1], cmd[2] - self.selection.b.line, self.selection.b.col = cmd[3], cmd[4] - end - - -- if next undo command is within the merge timeout then treat as a single - -- command and continue to execute it - local next = undo_stack[undo_stack.idx - 1] - if next and math.abs(cmd.time - next.time) < config.undo_merge_timeout then - return pop_undo(self, undo_stack, redo_stack) - end -end - - -function Doc:raw_insert(line, col, text, undo_stack, time) - -- split text into lines and merge with line at insertion point - local lines = split_lines(text) - local before = self.lines[line]:sub(1, col - 1) - local after = self.lines[line]:sub(col) - for i = 1, #lines - 1 do - lines[i] = lines[i] .. "\n" - end - lines[1] = before .. lines[1] - lines[#lines] = lines[#lines] .. after - - -- splice lines into line array - splice(self.lines, line, 1, lines) - - -- push undo - local line2, col2 = self:position_offset(line, col, #text) - push_undo(undo_stack, time, "selection", self:get_selection()) - push_undo(undo_stack, time, "remove", line, col, line2, col2) - - -- update highlighter and assure selection is in bounds - self.highlighter:invalidate(line) - self:sanitize_selection() -end - - -function Doc:raw_remove(line1, col1, line2, col2, undo_stack, time) - -- push undo - local text = self:get_text(line1, col1, line2, col2) - push_undo(undo_stack, time, "selection", self:get_selection()) - push_undo(undo_stack, time, "insert", line1, col1, text) - - -- get line content before/after removed text - local before = self.lines[line1]:sub(1, col1 - 1) - local after = self.lines[line2]:sub(col2) - - -- splice line into line array - splice(self.lines, line1, line2 - line1 + 1, { before .. after }) - - -- update highlighter and assure selection is in bounds - self.highlighter:invalidate(line1) - self:sanitize_selection() -end - - -function Doc:insert(line, col, text) - self.redo_stack = { idx = 1 } - line, col = self:sanitize_position(line, col) - self:raw_insert(line, col, text, self.undo_stack, system.get_time()) -end - - -function Doc:remove(line1, col1, line2, col2) - self.redo_stack = { idx = 1 } - line1, col1 = self:sanitize_position(line1, col1) - line2, col2 = self:sanitize_position(line2, col2) - line1, col1, line2, col2 = sort_positions(line1, col1, line2, col2) - self:raw_remove(line1, col1, line2, col2, self.undo_stack, system.get_time()) -end - - -function Doc:undo() - pop_undo(self, self.undo_stack, self.redo_stack) -end - - -function Doc:redo() - pop_undo(self, self.redo_stack, self.undo_stack) -end - - -function Doc:text_input(text) - if self:has_selection() then - self:delete_to() - end - local line, col = self:get_selection() - self:insert(line, col, text) - self:move_to(#text) -end - - -function Doc:replace(fn) - local line1, col1, line2, col2, swap - local had_selection = self:has_selection() - if had_selection then - line1, col1, line2, col2, swap = self:get_selection(true) - else - line1, col1, line2, col2 = 1, 1, #self.lines, #self.lines[#self.lines] - end - local old_text = self:get_text(line1, col1, line2, col2) - local new_text, n = fn(old_text) - if old_text ~= new_text then - self:insert(line2, col2, new_text) - self:remove(line1, col1, line2, col2) - if had_selection then - line2, col2 = self:position_offset(line1, col1, #new_text) - self:set_selection(line1, col1, line2, col2, swap) - end - end - return n -end - - -function Doc:delete_to(...) - local line, col = self:get_selection(true) - if self:has_selection() then - self:remove(self:get_selection()) - else - local line2, col2 = self:position_offset(line, col, ...) - self:remove(line, col, line2, col2) - line, col = sort_positions(line, col, line2, col2) - end - self:set_selection(line, col) -end - - -function Doc:move_to(...) - local line, col = self:get_selection() - self:set_selection(self:position_offset(line, col, ...)) -end - - -function Doc:select_to(...) - local line, col, line2, col2 = self:get_selection() - line, col = self:position_offset(line, col, ...) - self:set_selection(line, col, line2, col2) -end - - -return Doc diff --git a/tools/lite/data/core/doc/search.lua b/tools/lite/data/core/doc/search.lua deleted file mode 100644 index fe57523..0000000 --- a/tools/lite/data/core/doc/search.lua +++ /dev/null @@ -1,52 +0,0 @@ -local search = {} - -local default_opt = {} - - -local function pattern_lower(str) - if str:sub(1, 1) == "%" then - return str - end - return str:lower() -end - - -local function init_args(doc, line, col, text, opt) - opt = opt or default_opt - line, col = doc:sanitize_position(line, col) - - if opt.no_case then - if opt.pattern then - text = text:gsub("%%?.", pattern_lower) - else - text = text:lower() - end - end - - return doc, line, col, text, opt -end - - -function search.find(doc, line, col, text, opt) - doc, line, col, text, opt = init_args(doc, line, col, text, opt) - - for line = line, #doc.lines do - local line_text = doc.lines[line] - if opt.no_case then - line_text = line_text:lower() - end - local s, e = line_text:find(text, col, not opt.pattern) - if s then - return line, s, line, e + 1 - end - col = 1 - end - - if opt.wrap then - opt = { no_case = opt.no_case, pattern = opt.pattern } - return search.find(doc, 1, 1, text, opt) - end -end - - -return search diff --git a/tools/lite/data/core/doc/translate.lua b/tools/lite/data/core/doc/translate.lua deleted file mode 100644 index b084e89..0000000 --- a/tools/lite/data/core/doc/translate.lua +++ /dev/null @@ -1,136 +0,0 @@ -local common = require "core.common" -local config = require "core.config" - --- functions for translating a Doc position to another position these functions --- can be passed to Doc:move_to|select_to|delete_to() - -local translate = {} - - -local function is_non_word(char) - return config.non_word_chars:find(char, nil, true) -end - - -function translate.previous_char(doc, line, col) - repeat - line, col = doc:position_offset(line, col, -1) - until not common.is_utf8_cont(doc:get_char(line, col)) - return line, col -end - - -function translate.next_char(doc, line, col) - repeat - line, col = doc:position_offset(line, col, 1) - until not common.is_utf8_cont(doc:get_char(line, col)) - return line, col -end - - -function translate.previous_word_start(doc, line, col) - local prev - while line > 1 or col > 1 do - local l, c = doc:position_offset(line, col, -1) - local char = doc:get_char(l, c) - if prev and prev ~= char or not is_non_word(char) then - break - end - prev, line, col = char, l, c - end - return translate.start_of_word(doc, line, col) -end - - -function translate.next_word_end(doc, line, col) - local prev - local end_line, end_col = translate.end_of_doc(doc, line, col) - while line < end_line or col < end_col do - local char = doc:get_char(line, col) - if prev and prev ~= char or not is_non_word(char) then - break - end - line, col = doc:position_offset(line, col, 1) - prev = char - end - return translate.end_of_word(doc, line, col) -end - - -function translate.start_of_word(doc, line, col) - while true do - local line2, col2 = doc:position_offset(line, col, -1) - local char = doc:get_char(line2, col2) - if is_non_word(char) - or line == line2 and col == col2 then - break - end - line, col = line2, col2 - end - return line, col -end - - -function translate.end_of_word(doc, line, col) - while true do - local line2, col2 = doc:position_offset(line, col, 1) - local char = doc:get_char(line, col) - if is_non_word(char) - or line == line2 and col == col2 then - break - end - line, col = line2, col2 - end - return line, col -end - - -function translate.previous_block_start(doc, line, col) - while true do - line = line - 1 - if line <= 1 then - return 1, 1 - end - if doc.lines[line-1]:find("^%s*$") - and not doc.lines[line]:find("^%s*$") then - return line, (doc.lines[line]:find("%S")) - end - end -end - - -function translate.next_block_end(doc, line, col) - while true do - if line >= #doc.lines then - return #doc.lines, 1 - end - if doc.lines[line+1]:find("^%s*$") - and not doc.lines[line]:find("^%s*$") then - return line+1, #doc.lines[line+1] - end - line = line + 1 - end -end - - -function translate.start_of_line(doc, line, col) - return line, 1 -end - - -function translate.end_of_line(doc, line, col) - return line, math.huge -end - - -function translate.start_of_doc(doc, line, col) - return 1, 1 -end - - -function translate.end_of_doc(doc, line, col) - return #doc.lines, #doc.lines[#doc.lines] -end - - -return translate diff --git a/tools/lite/data/core/docview.lua b/tools/lite/data/core/docview.lua deleted file mode 100644 index 73191c2..0000000 --- a/tools/lite/data/core/docview.lua +++ /dev/null @@ -1,383 +0,0 @@ -local core = require "core" -local common = require "core.common" -local config = require "core.config" -local style = require "core.style" -local keymap = require "core.keymap" -local translate = require "core.doc.translate" -local View = require "core.view" - - -local DocView = View:extend() - - -local function move_to_line_offset(dv, line, col, offset) - local xo = dv.last_x_offset - if xo.line ~= line or xo.col ~= col then - xo.offset = dv:get_col_x_offset(line, col) - end - xo.line = line + offset - xo.col = dv:get_x_offset_col(line + offset, xo.offset) - return xo.line, xo.col -end - - -DocView.translate = { - ["previous_page"] = function(doc, line, col, dv) - local min, max = dv:get_visible_line_range() - return line - (max - min), 1 - end, - - ["next_page"] = function(doc, line, col, dv) - local min, max = dv:get_visible_line_range() - return line + (max - min), 1 - end, - - ["previous_line"] = function(doc, line, col, dv) - if line == 1 then - return 1, 1 - end - return move_to_line_offset(dv, line, col, -1) - end, - - ["next_line"] = function(doc, line, col, dv) - if line == #doc.lines then - return #doc.lines, math.huge - end - return move_to_line_offset(dv, line, col, 1) - end, -} - -local blink_period = 0.8 - - -function DocView:new(doc) - DocView.super.new(self) - self.cursor = "ibeam" - self.scrollable = true - self.doc = assert(doc) - self.font = "code_font" - self.last_x_offset = {} - self.blink_timer = 0 -end - - -function DocView:try_close(do_close) - if self.doc:is_dirty() - and #core.get_views_referencing_doc(self.doc) == 1 then - core.command_view:enter("Unsaved Changes; Confirm Close", function(_, item) - if item.text:match("^[cC]") then - do_close() - elseif item.text:match("^[sS]") then - self.doc:save() - do_close() - end - end, function(text) - local items = {} - if not text:find("^[^cC]") then table.insert(items, "Close Without Saving") end - if not text:find("^[^sS]") then table.insert(items, "Save And Close") end - return items - end) - else - do_close() - end -end - - -function DocView:get_name() - local post = self.doc:is_dirty() and "*" or "" - local name = self.doc:get_name() - return name:match("[^/%\\]*$") .. post -end - - -function DocView:get_scrollable_size() - return self:get_line_height() * (#self.doc.lines - 1) + self.size.y -end - - -function DocView:get_font() - return style[self.font] -end - - -function DocView:get_line_height() - return math.floor(self:get_font():get_height() * config.line_height) -end - - -function DocView:get_gutter_width() - return self:get_font():get_width(#self.doc.lines) + style.padding.x * 2 -end - - -function DocView:get_line_screen_position(idx) - local x, y = self:get_content_offset() - local lh = self:get_line_height() - local gw = self:get_gutter_width() - return x + gw, y + (idx-1) * lh + style.padding.y -end - - -function DocView:get_line_text_y_offset() - local lh = self:get_line_height() - local th = self:get_font():get_height() - return (lh - th) / 2 -end - - -function DocView:get_visible_line_range() - local x, y, x2, y2 = self:get_content_bounds() - local lh = self:get_line_height() - local minline = math.max(1, math.floor(y / lh)) - local maxline = math.min(#self.doc.lines, math.floor(y2 / lh) + 1) - return minline, maxline -end - - -function DocView:get_col_x_offset(line, col) - local text = self.doc.lines[line] - if not text then return 0 end - return self:get_font():get_width(text:sub(1, col - 1)) -end - - -function DocView:get_x_offset_col(line, x) - local text = self.doc.lines[line] - - local xoffset, last_i, i = 0, 1, 1 - for char in common.utf8_chars(text) do - local w = self:get_font():get_width(char) - if xoffset >= x then - return (xoffset - x > w / 2) and last_i or i - end - xoffset = xoffset + w - last_i = i - i = i + #char - end - - return #text -end - - -function DocView:resolve_screen_position(x, y) - local ox, oy = self:get_line_screen_position(1) - local line = math.floor((y - oy) / self:get_line_height()) + 1 - line = common.clamp(line, 1, #self.doc.lines) - local col = self:get_x_offset_col(line, x - ox) - return line, col -end - - -function DocView:scroll_to_line(line, ignore_if_visible, instant) - local min, max = self:get_visible_line_range() - if not (ignore_if_visible and line > min and line < max) then - local lh = self:get_line_height() - self.scroll.to.y = math.max(0, lh * (line - 1) - self.size.y / 2) - if instant then - self.scroll.y = self.scroll.to.y - end - end -end - - -function DocView:scroll_to_make_visible(line, col) - local min = self:get_line_height() * (line - 1) - local max = self:get_line_height() * (line + 2) - self.size.y - self.scroll.to.y = math.min(self.scroll.to.y, min) - self.scroll.to.y = math.max(self.scroll.to.y, max) - local gw = self:get_gutter_width() - local xoffset = self:get_col_x_offset(line, col) - local max = xoffset - self.size.x + gw + self.size.x / 5 - self.scroll.to.x = math.max(0, max) -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) - local caught = DocView.super.on_mouse_pressed(self, button, x, y, clicks) - if caught then - return - end - if keymap.modkeys["shift"] then - if clicks == 1 then - local line1, col1 = select(3, self.doc:get_selection()) - local line2, col2 = self:resolve_screen_position(x, y) - self.doc:set_selection(line2, col2, line1, col1) - end - else - local line, col = self:resolve_screen_position(x, y) - self.doc:set_selection(mouse_selection(self.doc, clicks, line, col, line, col)) - self.mouse_selecting = { line, col, clicks = clicks } - end - self.blink_timer = 0 -end - - -function DocView:on_mouse_moved(x, y, ...) - DocView.super.on_mouse_moved(self, x, y, ...) - - if self:scrollbar_overlaps_point(x, y) or self.dragging_scrollbar then - self.cursor = "arrow" - else - self.cursor = "ibeam" - end - - if self.mouse_selecting then - local l1, c1 = self:resolve_screen_position(x, y) - local l2, c2 = table.unpack(self.mouse_selecting) - local clicks = self.mouse_selecting.clicks - self.doc:set_selection(mouse_selection(self.doc, clicks, l1, c1, l2, c2)) - end -end - - -function DocView:on_mouse_released(button) - DocView.super.on_mouse_released(self, button) - self.mouse_selecting = nil -end - - -function DocView:on_text_input(text) - self.doc:text_input(text) -end - - -function DocView:update() - -- scroll to make caret visible and reset blink timer if it moved - local line, col = self.doc:get_selection() - if (line ~= self.last_line or col ~= self.last_col) and self.size.x > 0 then - if core.active_view == self then - self:scroll_to_make_visible(line, col) - end - self.blink_timer = 0 - self.last_line, self.last_col = line, col - end - - -- update blink timer - if self == core.active_view and not self.mouse_selecting then - local n = blink_period / 2 - local prev = self.blink_timer - self.blink_timer = (self.blink_timer + 1 / config.fps) % blink_period - if (self.blink_timer > n) ~= (prev > n) then - core.redraw = true - end - end - - DocView.super.update(self) -end - - -function DocView:draw_line_highlight(x, y) - local lh = self:get_line_height() - renderer.draw_rect(x, y, self.size.x, lh, style.line_highlight) -end - - -function DocView:draw_line_text(idx, x, y) - local tx, ty = x, y + self:get_line_text_y_offset() - local font = self:get_font() - for _, type, text in self.doc.highlighter:each_token(idx) do - local color = style.syntax[type] - tx = renderer.draw_text(font, text, tx, ty, color) - end -end - - -function DocView:draw_line_body(idx, x, y) - local line, col = self.doc:get_selection() - - -- draw selection if it overlaps this line - local line1, col1, line2, col2 = self.doc:get_selection(true) - if idx >= line1 and idx <= line2 then - local text = self.doc.lines[idx] - if line1 ~= idx then col1 = 1 end - if line2 ~= idx then col2 = #text + 1 end - local x1 = x + self:get_col_x_offset(idx, col1) - local x2 = x + self:get_col_x_offset(idx, col2) - local lh = self:get_line_height() - renderer.draw_rect(x1, y, x2 - x1, lh, style.selection) - end - - -- draw line highlight if caret is on this line - if config.highlight_current_line and not self.doc:has_selection() - and line == idx and core.active_view == self then - self:draw_line_highlight(x + self.scroll.x, y) - end - - -- draw line's text - self:draw_line_text(idx, x, y) - - -- draw caret if it overlaps this line - if line == idx and core.active_view == self - and self.blink_timer < blink_period / 2 - and system.window_has_focus() then - local lh = self:get_line_height() - local x1 = x + self:get_col_x_offset(line, col) - renderer.draw_rect(x1, y, style.caret_width, lh, style.caret) - end -end - - -function DocView:draw_line_gutter(idx, x, y) - local color = style.line_number - local line1, _, line2, _ = self.doc:get_selection(true) - if idx >= line1 and idx <= line2 then - color = style.line_number2 - end - local yoffset = self:get_line_text_y_offset() - x = x + style.padding.x - renderer.draw_text(self:get_font(), idx, x, y + yoffset, color) -end - - -function DocView:draw() - self:draw_background(style.background) - - local font = self:get_font() - font:set_tab_width(font:get_width(" ") * config.indent_size) - - local minline, maxline = self:get_visible_line_range() - local lh = self:get_line_height() - - local _, y = self:get_line_screen_position(minline) - local x = self.position.x - for i = minline, maxline do - self:draw_line_gutter(i, x, y) - y = y + lh - end - - local x, y = self:get_line_screen_position(minline) - local gw = self:get_gutter_width() - local pos = self.position - core.push_clip_rect(pos.x + gw, pos.y, self.size.x, self.size.y) - for i = minline, maxline do - self:draw_line_body(i, x, y) - y = y + lh - end - core.pop_clip_rect() - - self:draw_scrollbar() -end - - -return DocView diff --git a/tools/lite/data/core/init.lua b/tools/lite/data/core/init.lua deleted file mode 100644 index cef305e..0000000 --- a/tools/lite/data/core/init.lua +++ /dev/null @@ -1,480 +0,0 @@ -require "core.strict" -local common = require "core.common" -local config = require "core.config" -local style = require "core.style" -local command -local keymap -local RootView -local StatusView -local CommandView -local Doc - -local core = {} - - -local function project_scan_thread() - local function diff_files(a, b) - if #a ~= #b then return true end - for i, v in ipairs(a) do - if b[i].filename ~= v.filename - or b[i].modified ~= v.modified then - return true - end - end - end - - local function compare_file(a, b) - return a.filename < b.filename - end - - local function get_files(path, t) - coroutine.yield() - t = t or {} - local size_limit = config.file_size_limit * 10e5 - local all = system.list_dir(path) or {} - local dirs, files = {}, {} - - for _, file in ipairs(all) do - if not common.match_pattern(file, config.ignore_files) then - local file = (path ~= "." and path .. PATHSEP or "") .. file - local info = system.get_file_info(file) - if info and info.size < size_limit then - info.filename = file - table.insert(info.type == "dir" and dirs or files, info) - end - end - end - - table.sort(dirs, compare_file) - for _, f in ipairs(dirs) do - table.insert(t, f) - get_files(f.filename, t) - end - - table.sort(files, compare_file) - for _, f in ipairs(files) do - table.insert(t, f) - end - - return t - end - - while true do - -- get project files and replace previous table if the new table is - -- different - local t = get_files(".") - if diff_files(core.project_files, t) then - core.project_files = t - core.redraw = true - end - - -- wait for next scan - coroutine.yield(config.project_scan_rate) - end -end - - -function core.init() - command = require "core.command" - keymap = require "core.keymap" - RootView = require "core.rootview" - StatusView = require "core.statusview" - CommandView = require "core.commandview" - 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.clip_rect_stack = {{ 0,0,0,0 }} - core.log_items = {} - core.docs = {} - core.threads = setmetatable({}, { __mode = "k" }) - core.project_files = {} - core.redraw = true - - core.root_view = RootView() - core.command_view = CommandView() - core.status_view = StatusView() - - core.root_view.root_node:split("down", core.command_view, true) - core.root_view.root_node.b:split("down", core.status_view, true) - - core.add_thread(project_scan_thread) - command.add_defaults() - local got_plugin_error = not core.load_plugins() - local got_user_error = not core.try(require, "user") - local got_project_error = not core.load_project_module() - - for _, filename in ipairs(files) do - core.root_view:open_doc(core.open_doc(filename)) - end - - if got_plugin_error or got_user_error or got_project_error then - command.perform("core:open-log") - 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) - if force then - delete_temp_files() - os.exit() - end - local dirty_count = 0 - local dirty_name - for _, doc in ipairs(core.docs) do - if doc:is_dirty() then - dirty_count = dirty_count + 1 - dirty_name = doc:get_name() - end - end - if dirty_count > 0 then - local text - if dirty_count == 1 then - text = string.format("\"%s\" has unsaved changes. Quit anyway?", dirty_name) - else - text = string.format("%d docs have unsaved changes. Quit anyway?", dirty_count) - end - local confirm = system.show_confirm_dialog("Unsaved Changes", text) - if not confirm then return end - end - core.quit(true) -end - - -function core.load_plugins() - local no_errors = true - local files = system.list_dir(EXEDIR .. "/data/plugins") - for _, filename in ipairs(files) do - local modname = "plugins." .. filename:gsub(".lua$", "") - local ok = core.try(require, modname) - if ok then - core.log_quiet("Loaded plugin %q", modname) - else - no_errors = false - end - end - return no_errors -end - - -function core.load_project_module() - local filename = ".lite_project.lua" - if system.get_file_info(filename) then - return core.try(function() - local fn, err = loadfile(filename) - if not fn then error("Error when loading project module:\n\t" .. err) end - fn() - core.log_quiet("Loaded project module") - end) - end - return true -end - - -function core.reload_module(name) - local old = package.loaded[name] - package.loaded[name] = nil - local new = require(name) - if type(old) == "table" then - for k, v in pairs(new) do old[k] = v end - package.loaded[name] = old - 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) - local key = weak_ref or #core.threads + 1 - local fn = function() return core.try(f) end - core.threads[key] = { cr = coroutine.create(fn), wake = 0 } -end - - -function core.push_clip_rect(x, y, w, h) - local x2, y2, w2, h2 = table.unpack(core.clip_rect_stack[#core.clip_rect_stack]) - local r, b, r2, b2 = x+w, y+h, x2+w2, y2+h2 - x, y = math.max(x, x2), math.max(y, y2) - b, r = math.min(b, b2), math.min(r, r2) - w, h = r-x, b-y - table.insert(core.clip_rect_stack, { x, y, w, h }) - renderer.set_clip_rect(x, y, w, h) -end - - -function core.pop_clip_rect() - table.remove(core.clip_rect_stack) - local x, y, w, h = table.unpack(core.clip_rect_stack[#core.clip_rect_stack]) - renderer.set_clip_rect(x, y, w, h) -end - - -function core.open_doc(filename) - if filename then - -- try to find existing doc for filename - local abs_filename = system.absolute_path(filename) - for _, doc in ipairs(core.docs) do - if doc.filename - and abs_filename == system.absolute_path(doc.filename) then - return doc - end - end - end - -- no existing doc for filename; create new - local doc = Doc(filename) - table.insert(core.docs, doc) - core.log_quiet(filename and "Opened doc \"%s\"" or "Opened new doc", filename) - return doc -end - - -function core.get_views_referencing_doc(doc) - local res = {} - local views = core.root_view.root_node:get_children() - for _, view in ipairs(views) do - if view.doc == doc then table.insert(res, view) end - end - return res -end - - -local function log(icon, icon_color, fmt, ...) - local text = string.format(fmt, ...) - if icon then - core.status_view:show_message(icon, icon_color, text) - end - - local info = debug.getinfo(2, "Sl") - local at = string.format("%s:%d", info.short_src, info.currentline) - local item = { text = text, time = os.time(), at = at } - table.insert(core.log_items, item) - if #core.log_items > config.max_log_items then - table.remove(core.log_items, 1) - end - return item -end - - -function core.log(...) - return log("i", style.text, ...) -end - - -function core.log_quiet(...) - return log(nil, nil, ...) -end - - -function core.error(...) - return log("!", style.accent, ...) -end - - -function core.try(fn, ...) - local err - local ok, res = xpcall(fn, function(msg) - local item = core.error("%s", msg) - item.info = debug.traceback(nil, 2):gsub("\t", "") - err = msg - end, ...) - if ok then - return true, res - end - return false, err -end - - -function core.on_event(type, ...) - local did_keymap = false - if type == "textinput" then - core.root_view:on_text_input(...) - elseif type == "keypressed" then - did_keymap = keymap.on_key_pressed(...) - elseif type == "keyreleased" then - keymap.on_key_released(...) - elseif type == "mousemoved" then - core.root_view:on_mouse_moved(...) - elseif type == "mousepressed" then - core.root_view:on_mouse_pressed(...) - elseif type == "mousereleased" then - core.root_view:on_mouse_released(...) - elseif type == "mousewheel" then - core.root_view:on_mouse_wheel(...) - elseif type == "filedropped" then - local filename, mx, my = ... - local info = system.get_file_info(filename) - if info and info.type == "dir" then - system.exec(string.format("%q %q", EXEFILE, filename)) - else - 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 - elseif type == "quit" then - core.quit() - end - return did_keymap -end - - -function core.step() - -- handle events - local did_keymap = false - local mouse_moved = false - local mouse = { x = 0, y = 0, dx = 0, dy = 0 } - - for type, a,b,c,d in system.poll_event do - if type == "mousemoved" then - mouse_moved = true - mouse.x, mouse.y = a, b - mouse.dx, mouse.dy = mouse.dx + c, mouse.dy + d - elseif type == "textinput" and did_keymap then - did_keymap = false - else - local _, res = core.try(core.on_event, type, a, b, c, d) - did_keymap = res or did_keymap - end - core.redraw = true - end - if mouse_moved then - core.try(core.on_event, "mousemoved", mouse.x, mouse.y, mouse.dx, mouse.dy) - end - - local width, height = renderer.get_size() - - -- update - core.root_view.size.x, core.root_view.size.y = width, height - core.root_view:update() - if not core.redraw then return false end - core.redraw = false - - -- close unreferenced docs - for i = #core.docs, 1, -1 do - local doc = core.docs[i] - if #core.get_views_referencing_doc(doc) == 0 then - table.remove(core.docs, i) - core.log_quiet("Closed doc \"%s\"", doc:get_name()) - end - end - - -- update window title - local name = core.active_view:get_name() - local title = (name ~= "---") and (name .. " - lite") or "lite" - if title ~= core.window_title then - system.set_window_title(title) - core.window_title = title - end - - -- draw - renderer.begin_frame() - core.clip_rect_stack[1] = { 0, 0, width, height } - renderer.set_clip_rect(table.unpack(core.clip_rect_stack[1])) - core.root_view:draw() - renderer.end_frame() - return true -end - - -local run_threads = coroutine.wrap(function() - while true do - local max_time = 1 / config.fps - 0.004 - local ran_any_threads = false - - for k, thread in pairs(core.threads) do - -- run thread - if thread.wake < system.get_time() then - local _, wait = assert(coroutine.resume(thread.cr)) - if coroutine.status(thread.cr) == "dead" then - if type(k) == "number" then - table.remove(core.threads, k) - else - core.threads[k] = nil - end - elseif wait then - thread.wake = system.get_time() + wait - end - ran_any_threads = true - end - - -- stop running threads if we're about to hit the end of frame - if system.get_time() - core.frame_start > max_time then - coroutine.yield() - end - end - - if not ran_any_threads then coroutine.yield() end - end -end) - - -function core.run() - while true do - core.frame_start = system.get_time() - local did_redraw = core.step() - 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 - system.sleep(math.max(0, 1 / config.fps - elapsed)) - end -end - - -function core.on_error(err) - -- write error to file - local fp = io.open(EXEDIR .. "/error.txt", "wb") - fp:write("Error: " .. tostring(err) .. "\n") - fp:write(debug.traceback(nil, 4)) - fp:close() - -- save copy of all unsaved documents - for _, doc in ipairs(core.docs) do - if doc:is_dirty() and doc.filename then - doc:save(doc.filename .. "~") - end - end -end - - -return core diff --git a/tools/lite/data/core/keymap.lua b/tools/lite/data/core/keymap.lua deleted file mode 100644 index 4d48ed4..0000000 --- a/tools/lite/data/core/keymap.lua +++ /dev/null @@ -1,186 +0,0 @@ -local command = require "core.command" -local keymap = {} - -keymap.modkeys = {} -keymap.map = {} -keymap.reverse_map = {} - -local modkey_map = { - ["left ctrl"] = "ctrl", - ["right ctrl"] = "ctrl", - ["left shift"] = "shift", - ["right shift"] = "shift", - ["left alt"] = "alt", - ["right alt"] = "altgr", -} - -local modkeys = { "ctrl", "alt", "altgr", "shift" } - -local function key_to_stroke(k) - local stroke = "" - for _, mk in ipairs(modkeys) do - if keymap.modkeys[mk] then - stroke = stroke .. mk .. "+" - end - end - return stroke .. k -end - - -function keymap.add(map, overwrite) - for stroke, commands in pairs(map) do - if type(commands) == "string" then - commands = { commands } - end - if overwrite then - keymap.map[stroke] = commands - else - keymap.map[stroke] = keymap.map[stroke] or {} - for i = #commands, 1, -1 do - table.insert(keymap.map[stroke], 1, commands[i]) - end - end - for _, cmd in ipairs(commands) do - keymap.reverse_map[cmd] = stroke - end - end -end - - -function keymap.get_binding(cmd) - return keymap.reverse_map[cmd] -end - - -function keymap.on_key_pressed(k) - local mk = modkey_map[k] - if mk then - keymap.modkeys[mk] = true - -- work-around for windows where `altgr` is treated as `ctrl+alt` - if mk == "altgr" then - keymap.modkeys["ctrl"] = false - end - else - local stroke = key_to_stroke(k) - local commands = keymap.map[stroke] - if commands then - for _, cmd in ipairs(commands) do - local performed = command.perform(cmd) - if performed then break end - end - return true - end - end - return false -end - - -function keymap.on_key_released(k) - local mk = modkey_map[k] - if mk then - keymap.modkeys[mk] = false - end -end - - -keymap.add { - ["ctrl+shift+p"] = "core:find-command", - ["ctrl+p"] = "core:find-file", - ["ctrl+o"] = "core:open-file", - ["ctrl+n"] = "core:new-doc", - ["alt+return"] = "core:toggle-fullscreen", - - ["alt+shift+j"] = "root:split-left", - ["alt+shift+l"] = "root:split-right", - ["alt+shift+i"] = "root:split-up", - ["alt+shift+k"] = "root:split-down", - ["alt+j"] = "root:switch-to-left", - ["alt+l"] = "root:switch-to-right", - ["alt+i"] = "root:switch-to-up", - ["alt+k"] = "root:switch-to-down", - - ["ctrl+w"] = "root:close", - ["ctrl+tab"] = "root:switch-to-next-tab", - ["ctrl+shift+tab"] = "root:switch-to-previous-tab", - ["ctrl+pageup"] = "root:move-tab-left", - ["ctrl+pagedown"] = "root:move-tab-right", - ["alt+1"] = "root:switch-to-tab-1", - ["alt+2"] = "root:switch-to-tab-2", - ["alt+3"] = "root:switch-to-tab-3", - ["alt+4"] = "root:switch-to-tab-4", - ["alt+5"] = "root:switch-to-tab-5", - ["alt+6"] = "root:switch-to-tab-6", - ["alt+7"] = "root:switch-to-tab-7", - ["alt+8"] = "root:switch-to-tab-8", - ["alt+9"] = "root:switch-to-tab-9", - - ["ctrl+f"] = "find-replace:find", - ["ctrl+r"] = "find-replace:replace", - ["f3"] = "find-replace:repeat-find", - ["shift+f3"] = "find-replace:previous-find", - ["ctrl+g"] = "doc:go-to-line", - ["ctrl+s"] = "doc:save", - ["ctrl+shift+s"] = "doc:save-as", - - ["ctrl+z"] = "doc:undo", - ["ctrl+y"] = "doc:redo", - ["ctrl+x"] = "doc:cut", - ["ctrl+c"] = "doc:copy", - ["ctrl+v"] = "doc:paste", - ["escape"] = { "command:escape", "doc:select-none" }, - ["tab"] = { "command:complete", "doc:indent" }, - ["shift+tab"] = "doc:unindent", - ["backspace"] = "doc:backspace", - ["shift+backspace"] = "doc:backspace", - ["ctrl+backspace"] = "doc:delete-to-previous-word-start", - ["ctrl+shift+backspace"] = "doc:delete-to-previous-word-start", - ["delete"] = "doc:delete", - ["shift+delete"] = "doc:delete", - ["ctrl+delete"] = "doc:delete-to-next-word-end", - ["ctrl+shift+delete"] = "doc:delete-to-next-word-end", - ["return"] = { "command:submit", "doc:newline" }, - ["keypad enter"] = { "command:submit", "doc:newline" }, - ["ctrl+return"] = "doc:newline-below", - ["ctrl+shift+return"] = "doc:newline-above", - ["ctrl+j"] = "doc:join-lines", - ["ctrl+a"] = "doc:select-all", - ["ctrl+d"] = { "find-replace:select-next", "doc:select-word" }, - ["ctrl+l"] = "doc:select-lines", - ["ctrl+/"] = "doc:toggle-line-comments", - ["ctrl+up"] = "doc:move-lines-up", - ["ctrl+down"] = "doc:move-lines-down", - ["ctrl+shift+d"] = "doc:duplicate-lines", - ["ctrl+shift+k"] = "doc:delete-lines", - - ["left"] = "doc:move-to-previous-char", - ["right"] = "doc:move-to-next-char", - ["up"] = { "command:select-previous", "doc:move-to-previous-line" }, - ["down"] = { "command:select-next", "doc:move-to-next-line" }, - ["ctrl+left"] = "doc:move-to-previous-word-start", - ["ctrl+right"] = "doc:move-to-next-word-end", - ["ctrl+["] = "doc:move-to-previous-block-start", - ["ctrl+]"] = "doc:move-to-next-block-end", - ["home"] = "doc:move-to-start-of-line", - ["end"] = "doc:move-to-end-of-line", - ["ctrl+home"] = "doc:move-to-start-of-doc", - ["ctrl+end"] = "doc:move-to-end-of-doc", - ["pageup"] = "doc:move-to-previous-page", - ["pagedown"] = "doc:move-to-next-page", - - ["shift+left"] = "doc:select-to-previous-char", - ["shift+right"] = "doc:select-to-next-char", - ["shift+up"] = "doc:select-to-previous-line", - ["shift+down"] = "doc:select-to-next-line", - ["ctrl+shift+left"] = "doc:select-to-previous-word-start", - ["ctrl+shift+right"] = "doc:select-to-next-word-end", - ["ctrl+shift+["] = "doc:select-to-previous-block-start", - ["ctrl+shift+]"] = "doc:select-to-next-block-end", - ["shift+home"] = "doc:select-to-start-of-line", - ["shift+end"] = "doc:select-to-end-of-line", - ["ctrl+shift+home"] = "doc:select-to-start-of-doc", - ["ctrl+shift+end"] = "doc:select-to-end-of-doc", - ["shift+pageup"] = "doc:select-to-previous-page", - ["shift+pagedown"] = "doc:select-to-next-page", -} - -return keymap diff --git a/tools/lite/data/core/logview.lua b/tools/lite/data/core/logview.lua deleted file mode 100644 index d7142fb..0000000 --- a/tools/lite/data/core/logview.lua +++ /dev/null @@ -1,74 +0,0 @@ -local core = require "core" -local style = require "core.style" -local View = require "core.view" - - -local LogView = View:extend() - - -function LogView:new() - LogView.super.new(self) - self.last_item = core.log_items[#core.log_items] - self.scrollable = true - self.yoffset = 0 -end - - -function LogView:get_name() - return "Log" -end - - -function LogView:update() - local item = core.log_items[#core.log_items] - if self.last_item ~= item then - self.last_item = item - self.scroll.to.y = 0 - self.yoffset = -(style.font:get_height() + style.padding.y) - end - - self:move_towards("yoffset", 0) - - LogView.super.update(self) -end - - -local function draw_text_multiline(font, text, x, y, color) - local th = font:get_height() - local resx, resy = x, y - for line in text:gmatch("[^\n]+") do - resy = y - resx = renderer.draw_text(style.font, line, x, y, color) - y = y + th - end - return resx, resy -end - - -function LogView:draw() - self:draw_background(style.background) - - local ox, oy = self:get_content_offset() - local th = style.font:get_height() - local y = oy + style.padding.y + self.yoffset - - for i = #core.log_items, 1, -1 do - local x = ox + style.padding.x - local item = core.log_items[i] - local time = os.date(nil, item.time) - x = renderer.draw_text(style.font, time, x, y, style.dim) - x = x + style.padding.x - local subx = x - x, y = draw_text_multiline(style.font, item.text, x, y, style.text) - renderer.draw_text(style.font, " at " .. item.at, x, y, style.dim) - y = y + th - if item.info then - subx, y = draw_text_multiline(style.font, item.info, subx, y, style.dim) - y = y + th - end - y = y + style.padding.y - end -end - - -return LogView diff --git a/tools/lite/data/core/object.lua b/tools/lite/data/core/object.lua deleted file mode 100644 index af41b7e..0000000 --- a/tools/lite/data/core/object.lua +++ /dev/null @@ -1,58 +0,0 @@ -local Object = {} -Object.__index = Object - - -function Object:new() -end - - -function Object:extend() - local cls = {} - for k, v in pairs(self) do - if k:find("__") == 1 then - cls[k] = v - end - end - cls.__index = cls - cls.super = self - setmetatable(cls, self) - return cls -end - - -function Object:implement(...) - for _, cls in pairs({...}) do - for k, v in pairs(cls) do - if self[k] == nil and type(v) == "function" then - self[k] = v - end - end - end -end - - -function Object:is(T) - local mt = getmetatable(self) - while mt do - if mt == T then - return true - end - mt = getmetatable(mt) - end - return false -end - - -function Object:__tostring() - return "Object" -end - - -function Object:__call(...) - local obj = setmetatable({}, self) - obj:new(...) - return obj -end - - -return Object diff --git a/tools/lite/data/core/rootview.lua b/tools/lite/data/core/rootview.lua deleted file mode 100644 index 389525f..0000000 --- a/tools/lite/data/core/rootview.lua +++ /dev/null @@ -1,504 +0,0 @@ -local core = require "core" -local common = require "core.common" -local style = require "core.style" -local keymap = require "core.keymap" -local Object = require "core.object" -local View = require "core.view" -local DocView = require "core.docview" - - -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() - self:draw_background(style.background) - local w, h = draw_text(0, 0, { 0, 0, 0, 0 }) - local x = self.position.x + math.max(style.padding.x, (self.size.x - w) / 2) - local y = self.position.y + (self.size.y - h) / 2 - draw_text(x, y, style.dim) -end - - - -local Node = Object:extend() - -function Node:new(type) - self.type = type or "leaf" - self.position = { x = 0, y = 0 } - self.size = { x = 0, y = 0 } - self.views = {} - self.divider = 0.5 - if self.type == "leaf" then - self:add_view(EmptyView()) - end -end - - -function Node:propagate(fn, ...) - self.a[fn](self.a, ...) - self.b[fn](self.b, ...) -end - - -function Node:on_mouse_moved(x, y, ...) - self.hovered_tab = self:get_tab_overlapping_point(x, y) - if self.type == "leaf" then - self.active_view:on_mouse_moved(x, y, ...) - else - self:propagate("on_mouse_moved", x, y, ...) - end -end - - -function Node:on_mouse_released(...) - if self.type == "leaf" then - self.active_view:on_mouse_released(...) - else - self:propagate("on_mouse_released", ...) - end -end - - -function Node:consume(node) - for k, _ in pairs(self) do self[k] = nil end - for k, v in pairs(node) do self[k] = v end -end - - -local type_map = { up="vsplit", down="vsplit", left="hsplit", right="hsplit" } - -function Node:split(dir, view, locked) - assert(self.type == "leaf", "Tried to split non-leaf node") - local type = assert(type_map[dir], "Invalid direction") - local last_active = core.active_view - local child = Node() - child:consume(self) - self:consume(Node(type)) - self.a = child - self.b = Node() - if view then self.b:add_view(view) end - if locked then - self.b.locked = locked - core.set_active_view(last_active) - end - if dir == "up" or dir == "left" then - self.a, self.b = self.b, self.a - end - return child -end - - -function Node:close_active_view(root) - local do_close = function() - if #self.views > 1 then - local idx = self:get_view_idx(self.active_view) - table.remove(self.views, idx) - self:set_active_view(self.views[idx] or self.views[#self.views]) - else - local parent = self:get_parent_node(root) - local is_a = (parent.a == self) - local other = parent[is_a and "b" or "a"] - if other:get_locked_size() then - self.views = {} - self:add_view(EmptyView()) - else - parent:consume(other) - local p = parent - while p.type ~= "leaf" do - p = p[is_a and "a" or "b"] - end - p:set_active_view(p.active_view) - end - end - core.last_active_view = nil - end - self.active_view:try_close(do_close) -end - - -function Node:add_view(view) - 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 - table.remove(self.views) - end - table.insert(self.views, view) - self:set_active_view(view) -end - - -function Node:set_active_view(view) - assert(self.type == "leaf", "Tried to set active view on non-leaf node") - self.active_view = view - core.set_active_view(view) -end - - -function Node:get_view_idx(view) - for i, v in ipairs(self.views) do - if v == view then return i end - end -end - - -function Node:get_node_for_view(view) - for _, v in ipairs(self.views) do - if v == view then return self end - end - if self.type ~= "leaf" then - return self.a:get_node_for_view(view) or self.b:get_node_for_view(view) - end -end - - -function Node:get_parent_node(root) - if root.a == self or root.b == self then - return root - elseif root.type ~= "leaf" then - return self:get_parent_node(root.a) or self:get_parent_node(root.b) - end -end - - -function Node:get_children(t) - t = t or {} - for _, view in ipairs(self.views) do - table.insert(t, view) - end - if self.a then self.a:get_children(t) end - if self.b then self.b:get_children(t) end - return t -end - - -function Node:get_divider_overlapping_point(px, py) - if self.type ~= "leaf" then - local p = 6 - local x, y, w, h = self:get_divider_rect() - x, y = x - p, y - p - w, h = w + p * 2, h + p * 2 - if px > x and py > y and px < x + w and py < y + h then - return self - end - return self.a:get_divider_overlapping_point(px, py) - or self.b:get_divider_overlapping_point(px, py) - end -end - - -function Node:get_tab_overlapping_point(px, py) - if #self.views == 1 then return nil end - local x, y, w, h = self:get_tab_rect(1) - if px >= x and py >= y and px < x + w * #self.views and py < y + h then - return math.floor((px - x) / w) + 1 - end -end - - -function Node:get_child_overlapping_point(x, y) - local child - if self.type == "leaf" then - return self - elseif self.type == "hsplit" then - child = (x < self.b.position.x) and self.a or self.b - elseif self.type == "vsplit" then - child = (y < self.b.position.y) and self.a or self.b - end - return child:get_child_overlapping_point(x, y) -end - - -function Node:get_tab_rect(idx) - local tw = math.min(style.tab_width, math.ceil(self.size.x / #self.views)) - local h = style.font:get_height() + style.padding.y * 2 - return self.position.x + (idx-1) * tw, self.position.y, tw, h -end - - -function Node:get_divider_rect() - local x, y = self.position.x, self.position.y - if self.type == "hsplit" then - return x + self.a.size.x, y, style.divider_size, self.size.y - elseif self.type == "vsplit" then - return x, y + self.a.size.y, self.size.x, style.divider_size - end -end - - -function Node:get_locked_size() - if self.type == "leaf" then - if self.locked then - local size = self.active_view.size - return size.x, size.y - end - else - local x1, y1 = self.a:get_locked_size() - local x2, y2 = self.b:get_locked_size() - if x1 and x2 then - local dsx = (x1 < 1 or x2 < 1) and 0 or style.divider_size - local dsy = (y1 < 1 or y2 < 1) and 0 or style.divider_size - return x1 + x2 + dsx, y1 + y2 + dsy - end - end -end - - -local function copy_position_and_size(dst, src) - dst.position.x, dst.position.y = src.position.x, src.position.y - dst.size.x, dst.size.y = src.size.x, src.size.y -end - - --- calculating the sizes is the same for hsplits and vsplits, except the x/y --- axis are swapped; this function lets us use the same code for both -local function calc_split_sizes(self, x, y, x1, x2) - local n - local ds = (x1 and x1 < 1 or x2 and x2 < 1) and 0 or style.divider_size - if x1 then - n = x1 + ds - elseif x2 then - n = self.size[x] - x2 - else - n = math.floor(self.size[x] * self.divider) - end - self.a.position[x] = self.position[x] - self.a.position[y] = self.position[y] - self.a.size[x] = n - ds - self.a.size[y] = self.size[y] - self.b.position[x] = self.position[x] + n - self.b.position[y] = self.position[y] - self.b.size[x] = self.size[x] - n - self.b.size[y] = self.size[y] -end - - -function Node:update_layout() - if self.type == "leaf" then - local av = self.active_view - if #self.views > 1 then - local _, _, _, th = self:get_tab_rect(1) - av.position.x, av.position.y = self.position.x, self.position.y + th - av.size.x, av.size.y = self.size.x, self.size.y - th - else - copy_position_and_size(av, self) - end - else - local x1, y1 = self.a:get_locked_size() - local x2, y2 = self.b:get_locked_size() - if self.type == "hsplit" then - calc_split_sizes(self, "x", "y", x1, x2) - elseif self.type == "vsplit" then - calc_split_sizes(self, "y", "x", y1, y2) - end - self.a:update_layout() - self.b:update_layout() - end -end - - -function Node:update() - if self.type == "leaf" then - for _, view in ipairs(self.views) do - view:update() - end - else - self.a:update() - self.b:update() - end -end - - -function Node:draw_tabs() - local x, y, _, h = self:get_tab_rect(1) - local ds = style.divider_size - core.push_clip_rect(x, y, self.size.x, h) - renderer.draw_rect(x, y, self.size.x, h, style.background2) - renderer.draw_rect(x, y + h - ds, self.size.x, ds, style.divider) - - for i, view in ipairs(self.views) do - local x, y, w, h = self:get_tab_rect(i) - local text = view:get_name() - local color = style.dim - if view == self.active_view then - color = style.text - renderer.draw_rect(x, y, w, h, style.background) - renderer.draw_rect(x + w, y, ds, h, style.divider) - renderer.draw_rect(x - ds, y, ds, h, style.divider) - end - if i == self.hovered_tab then - color = style.text - end - core.push_clip_rect(x, y, w, h) - x, w = x + style.padding.x, w - style.padding.x * 2 - 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() - end - - core.pop_clip_rect() -end - - -function Node:draw() - if self.type == "leaf" then - if #self.views > 1 then - self:draw_tabs() - end - local pos, size = self.active_view.position, self.active_view.size - core.push_clip_rect(pos.x, pos.y, size.x + pos.x % 1, size.y + pos.y % 1) - self.active_view:draw() - core.pop_clip_rect() - else - local x, y, w, h = self:get_divider_rect() - renderer.draw_rect(x, y, w, h, style.divider) - self:propagate("draw") - end -end - - - -local RootView = View:extend() - -function RootView:new() - RootView.super.new(self) - self.root_node = Node() - self.deferred_draws = {} - self.mouse = { x = 0, y = 0 } -end - - -function RootView:defer_draw(fn, ...) - table.insert(self.deferred_draws, 1, { fn = fn, ... }) -end - - -function RootView:get_active_node() - return self.root_node:get_node_for_view(core.active_view) -end - - -function RootView:open_doc(doc) - 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") - for i, view in ipairs(node.views) do - if view.doc == doc then - node:set_active_view(node.views[i]) - return view - end - end - local view = DocView(doc) - node:add_view(view) - self.root_node:update_layout() - view:scroll_to_line(view.doc:get_selection(), true, true) - return view -end - - -function RootView:on_mouse_pressed(button, x, y, clicks) - local div = self.root_node:get_divider_overlapping_point(x, y) - if div then - self.dragged_divider = div - return - end - local node = self.root_node:get_child_overlapping_point(x, y) - local idx = node:get_tab_overlapping_point(x, y) - if idx then - node:set_active_view(node.views[idx]) - if button == "middle" then - node:close_active_view(self.root_node) - end - else - core.set_active_view(node.active_view) - node.active_view:on_mouse_pressed(button, x, y, clicks) - end -end - - -function RootView:on_mouse_released(...) - if self.dragged_divider then - self.dragged_divider = nil - end - self.root_node:on_mouse_released(...) -end - - -function RootView:on_mouse_moved(x, y, dx, dy) - if self.dragged_divider then - local node = self.dragged_divider - if node.type == "hsplit" then - node.divider = node.divider + dx / node.size.x - else - node.divider = node.divider + dy / node.size.y - end - node.divider = common.clamp(node.divider, 0.01, 0.99) - return - end - - self.mouse.x, self.mouse.y = x, y - self.root_node:on_mouse_moved(x, y, dx, dy) - - local node = self.root_node:get_child_overlapping_point(x, y) - local div = self.root_node:get_divider_overlapping_point(x, y) - if div then - system.set_cursor(div.type == "hsplit" and "sizeh" or "sizev") - elseif node:get_tab_overlapping_point(x, y) then - system.set_cursor("arrow") - else - system.set_cursor(node.active_view.cursor) - end -end - - -function RootView:on_mouse_wheel(...) - local x, y = self.mouse.x, self.mouse.y - local node = self.root_node:get_child_overlapping_point(x, y) - node.active_view:on_mouse_wheel(...) -end - - -function RootView:on_text_input(...) - core.active_view:on_text_input(...) -end - - -function RootView:update() - copy_position_and_size(self.root_node, self) - self.root_node:update() - self.root_node:update_layout() -end - - -function RootView:draw() - self.root_node:draw() - while #self.deferred_draws > 0 do - local t = table.remove(self.deferred_draws) - t.fn(table.unpack(t)) - end -end - - -return RootView diff --git a/tools/lite/data/core/statusview.lua b/tools/lite/data/core/statusview.lua deleted file mode 100644 index 67a4c8b..0000000 --- a/tools/lite/data/core/statusview.lua +++ /dev/null @@ -1,141 +0,0 @@ -local core = require "core" -local common = require "core.common" -local command = require "core.command" -local config = require "core.config" -local style = require "core.style" -local DocView = require "core.docview" -local LogView = require "core.logview" -local View = require "core.view" - - -local StatusView = View:extend() - -StatusView.separator = " " -StatusView.separator2 = " | " - - -function StatusView:new() - StatusView.super.new(self) - self.message_timeout = 0 - self.message = {} -end - - -function StatusView:on_mouse_pressed() - core.set_active_view(core.last_active_view) - if system.get_time() < self.message_timeout - and not core.active_view:is(LogView) then - command.perform "core:open-log" - end -end - - -function StatusView:show_message(icon, icon_color, text) - self.message = { - icon_color, style.icon_font, icon, - style.dim, style.font, StatusView.separator2, style.text, text - } - self.message_timeout = system.get_time() + config.message_timeout -end - - -function StatusView:update() - self.size.y = style.font:get_height() + style.padding.y * 2 - - if system.get_time() < self.message_timeout then - self.scroll.to.y = self.size.y - else - self.scroll.to.y = 0 - end - - StatusView.super.update(self) -end - - -local function draw_items(self, items, x, y, draw_fn) - local font = style.font - local color = style.text - - for _, item in ipairs(items) do - if type(item) == "userdata" then - font = item - elseif type(item) == "table" then - color = item - else - x = draw_fn(font, color, item, nil, x, y, 0, self.size.y) - end - end - - return x -end - - -local function text_width(font, _, text, _, x) - return x + font:get_width(text) -end - - -function StatusView:draw_items(items, right_align, yoffset) - local x, y = self:get_content_offset() - y = y + (yoffset or 0) - if right_align then - local w = draw_items(self, items, 0, 0, text_width) - x = x + self.size.x - w - style.padding.x - draw_items(self, items, x, y, common.draw_text) - else - x = x + style.padding.x - draw_items(self, items, x, y, common.draw_text) - end -end - - -function StatusView:get_items() - if getmetatable(core.active_view) == DocView then - local dv = core.active_view - local line, col = dv.doc:get_selection() - local dirty = dv.doc:is_dirty() - - return { - dirty and style.accent or style.text, style.icon_font, "f", - style.dim, style.font, self.separator2, style.text, - dv.doc.filename and style.text or style.dim, dv.doc:get_name(), - style.text, - self.separator, - "line: ", line, - self.separator, - col > config.line_limit and style.accent or style.text, "col: ", col, - style.text, - self.separator, - string.format("%d%%", line / #dv.doc.lines * 100), - }, { - style.icon_font, "g", - style.font, style.dim, self.separator2, style.text, - #dv.doc.lines, " lines", - self.separator, - dv.doc.crlf and "CRLF" or "LF" - } - end - - return {}, { - style.icon_font, "g", - style.font, style.dim, self.separator2, - #core.docs, style.text, " / ", - #core.project_files, " files" - } -end - - -function StatusView:draw() - self:draw_background(style.background2) - - if self.message then - self:draw_items(self.message, false, self.size.y) - end - - local left, right = self:get_items() - self:draw_items(left) - self:draw_items(right, true) -end - - -return StatusView diff --git a/tools/lite/data/core/strict.lua b/tools/lite/data/core/strict.lua deleted file mode 100644 index 7d4b9da..0000000 --- a/tools/lite/data/core/strict.lua +++ /dev/null @@ -1,26 +0,0 @@ -local strict = {} -strict.defined = {} - - --- used to define a global variable -function global(t) - for k, v in pairs(t) do - strict.defined[k] = true - rawset(_G, k, v) - end -end - - -function strict.__newindex(t, k, v) - error("cannot set undefined variable: " .. k, 2) -end - - -function strict.__index(t, k) - if not strict.defined[k] then - error("cannot get undefined variable: " .. k, 2) - end -end - - -setmetatable(_G, strict) diff --git a/tools/lite/data/core/style.lua b/tools/lite/data/core/style.lua deleted file mode 100644 index ab597c2..0000000 --- a/tools/lite/data/core/style.lua +++ /dev/null @@ -1,42 +0,0 @@ -local common = require "core.common" -local style = {} - -style.padding = { x = common.round(14 * SCALE), y = common.round(7 * SCALE) } -style.divider_size = common.round(1 * SCALE) -style.scrollbar_size = common.round(4 * SCALE) -style.caret_width = common.round(2 * SCALE) -style.tab_width = common.round(170 * SCALE) - -style.font = renderer.font.load(EXEDIR .. "/data/fonts/font.ttf", 14 * SCALE) -style.big_font = renderer.font.load(EXEDIR .. "/data/fonts/font.ttf", 34 * SCALE) -style.icon_font = renderer.font.load(EXEDIR .. "/data/fonts/icons.ttf", 14 * SCALE) -style.code_font = renderer.font.load(EXEDIR .. "/data/fonts/monospace.ttf", 13.5 * SCALE) - -style.background = { common.color "#2e2e32" } -style.background2 = { common.color "#252529" } -style.background3 = { common.color "#252529" } -style.text = { common.color "#97979c" } -style.caret = { common.color "#93DDFA" } -style.accent = { common.color "#e1e1e6" } -style.dim = { common.color "#525257" } -style.divider = { common.color "#202024" } -style.selection = { common.color "#48484f" } -style.line_number = { common.color "#525259" } -style.line_number2 = { common.color "#83838f" } -style.line_highlight = { common.color "#343438" } -style.scrollbar = { common.color "#414146" } -style.scrollbar2 = { common.color "#4b4b52" } - -style.syntax = {} -style.syntax["normal"] = { common.color "#e1e1e6" } -style.syntax["symbol"] = { common.color "#e1e1e6" } -style.syntax["comment"] = { common.color "#676b6f" } -style.syntax["keyword"] = { common.color "#E58AC9" } -style.syntax["keyword2"] = { common.color "#F77483" } -style.syntax["number"] = { common.color "#FFA94D" } -style.syntax["literal"] = { common.color "#FFA94D" } -style.syntax["string"] = { common.color "#f7c95c" } -style.syntax["operator"] = { common.color "#93DDFA" } -style.syntax["function"] = { common.color "#93DDFA" } - -return style diff --git a/tools/lite/data/core/syntax.lua b/tools/lite/data/core/syntax.lua deleted file mode 100644 index a763ac7..0000000 --- a/tools/lite/data/core/syntax.lua +++ /dev/null @@ -1,30 +0,0 @@ -local common = require "core.common" - -local syntax = {} -syntax.items = {} - -local plain_text_syntax = { patterns = {}, symbols = {} } - - -function syntax.add(t) - table.insert(syntax.items, t) -end - - -local function find(string, field) - for i = #syntax.items, 1, -1 do - local t = syntax.items[i] - if common.match_pattern(string, t[field] or {}) then - return t - end - end -end - -function syntax.get(filename, header) - return find(filename, "files") - or find(header, "headers") - or plain_text_syntax -end - - -return syntax diff --git a/tools/lite/data/core/tokenizer.lua b/tools/lite/data/core/tokenizer.lua deleted file mode 100644 index 98aafc7..0000000 --- a/tools/lite/data/core/tokenizer.lua +++ /dev/null @@ -1,112 +0,0 @@ -local tokenizer = {} - - -local function push_token(t, type, text) - local prev_type = t[#t-1] - local prev_text = t[#t] - if prev_type and (prev_type == type or prev_text:find("^%s*$")) then - t[#t-1] = type - t[#t] = prev_text .. text - else - table.insert(t, type) - table.insert(t, text) - end -end - - -local function is_escaped(text, idx, esc) - local byte = esc:byte() - local count = 0 - for i = idx - 1, 1, -1 do - if text:byte(i) ~= byte then break end - count = count + 1 - end - return count % 2 == 1 -end - - -local function find_non_escaped(text, pattern, offset, esc) - while true do - local s, e = text:find(pattern, offset) - if not s then break end - if esc and is_escaped(text, s, esc) then - offset = e + 1 - else - return s, e - end - end -end - - -function tokenizer.tokenize(syntax, text, state) - local res = {} - local i = 1 - - if #syntax.patterns == 0 then - return { "normal", text } - end - - while i <= #text do - -- continue trying to match the end pattern of a pair if we have a state set - if state then - local p = syntax.patterns[state] - local s, e = find_non_escaped(text, p.pattern[2], i, p.pattern[3]) - - if s then - push_token(res, p.type, text:sub(i, e)) - state = nil - i = e + 1 - else - push_token(res, p.type, text:sub(i)) - break - end - end - - -- find matching pattern - local matched = false - for n, p in ipairs(syntax.patterns) do - local pattern = (type(p.pattern) == "table") and p.pattern[1] or p.pattern - local s, e = text:find("^" .. pattern, i) - - if s then - -- matched pattern; make and add token - local t = text:sub(s, e) - push_token(res, syntax.symbols[t] or p.type, t) - - -- update state if this was a start|end pattern pair - if type(p.pattern) == "table" then - state = n - end - - -- move cursor past this token - i = e + 1 - matched = true - break - end - end - - -- consume character if we didn't match - if not matched then - push_token(res, "normal", text:sub(i, i)) - i = i + 1 - end - end - - return res, state -end - - -local function iter(t, i) - i = i + 2 - local type, text = t[i], t[i+1] - if type then - return i, type, text - end -end - -function tokenizer.each_token(t) - return iter, t, -1 -end - - -return tokenizer diff --git a/tools/lite/data/core/view.lua b/tools/lite/data/core/view.lua deleted file mode 100644 index ae978a9..0000000 --- a/tools/lite/data/core/view.lua +++ /dev/null @@ -1,151 +0,0 @@ -local core = require "core" -local config = require "core.config" -local style = require "core.style" -local common = require "core.common" -local Object = require "core.object" - - -local View = Object:extend() - - -function View:new() - self.position = { x = 0, y = 0 } - self.size = { x = 0, y = 0 } - self.scroll = { x = 0, y = 0, to = { x = 0, y = 0 } } - self.cursor = "arrow" - self.scrollable = false -end - - -function View:move_towards(t, k, dest, rate) - if type(t) ~= "table" then - return self:move_towards(self, t, k, dest, rate) - end - local val = t[k] - if math.abs(val - dest) < 0.5 then - t[k] = dest - else - t[k] = common.lerp(val, dest, rate or 0.5) - end - if val ~= dest then - core.redraw = true - end -end - - -function View:try_close(do_close) - do_close() -end - - -function View:get_name() - return "---" -end - - -function View:get_scrollable_size() - return math.huge -end - - -function View:get_scrollbar_rect() - local sz = self:get_scrollable_size() - if sz <= self.size.y or sz == math.huge then - return 0, 0, 0, 0 - end - local h = math.max(20, self.size.y * self.size.y / sz) - return - self.position.x + self.size.x - style.scrollbar_size, - self.position.y + self.scroll.y * (self.size.y - h) / (sz - self.size.y), - style.scrollbar_size, - h -end - - -function View:scrollbar_overlaps_point(x, y) - local sx, sy, sw, sh = self:get_scrollbar_rect() - return x >= sx - sw * 3 and x < sx + sw and y >= sy and y < sy + sh -end - - -function View:on_mouse_pressed(button, x, y, clicks) - if self:scrollbar_overlaps_point(x, y) then - self.dragging_scrollbar = true - return true - end -end - - -function View:on_mouse_released(button, x, y) - self.dragging_scrollbar = false -end - - -function View:on_mouse_moved(x, y, dx, dy) - if self.dragging_scrollbar then - local delta = self:get_scrollable_size() / self.size.y * dy - self.scroll.to.y = self.scroll.to.y + delta - end - self.hovered_scrollbar = self:scrollbar_overlaps_point(x, y) -end - - -function View:on_text_input(text) - -- no-op -end - - -function View:on_mouse_wheel(y) - if self.scrollable then - self.scroll.to.y = self.scroll.to.y + y * -config.mouse_wheel_scroll - end -end - - -function View:get_content_bounds() - local x = self.scroll.x - local y = self.scroll.y - return x, y, x + self.size.x, y + self.size.y -end - - -function View:get_content_offset() - local x = common.round(self.position.x - self.scroll.x) - local y = common.round(self.position.y - self.scroll.y) - return x, y -end - - -function View:clamp_scroll_position() - local max = self:get_scrollable_size() - self.size.y - self.scroll.to.y = common.clamp(self.scroll.to.y, 0, max) -end - - -function View:update() - self:clamp_scroll_position() - self:move_towards(self.scroll, "x", self.scroll.to.x, 0.3) - self:move_towards(self.scroll, "y", self.scroll.to.y, 0.3) -end - - -function View:draw_background(color) - local x, y = self.position.x, self.position.y - local w, h = self.size.x, self.size.y - renderer.draw_rect(x, y, w + x % 1, h + y % 1, color) -end - - -function View:draw_scrollbar() - local x, y, w, h = self:get_scrollbar_rect() - local highlight = self.hovered_scrollbar or self.dragging_scrollbar - local color = highlight and style.scrollbar2 or style.scrollbar - renderer.draw_rect(x, y, w, h, color) -end - - -function View:draw() -end - - -return View diff --git a/tools/lite/data/fonts/font.ttf b/tools/lite/data/fonts/font.ttf deleted file mode 100644 index 2b6392f..0000000 Binary files a/tools/lite/data/fonts/font.ttf and /dev/null differ diff --git a/tools/lite/data/fonts/icons.ttf b/tools/lite/data/fonts/icons.ttf deleted file mode 100644 index d74fe73..0000000 Binary files a/tools/lite/data/fonts/icons.ttf and /dev/null differ diff --git a/tools/lite/data/fonts/monospace.ttf b/tools/lite/data/fonts/monospace.ttf deleted file mode 100644 index 5919b5d..0000000 Binary files a/tools/lite/data/fonts/monospace.ttf and /dev/null differ diff --git a/tools/lite/data/plugins/autocomplete.lua b/tools/lite/data/plugins/autocomplete.lua deleted file mode 100644 index 79e4513..0000000 --- a/tools/lite/data/plugins/autocomplete.lua +++ /dev/null @@ -1,284 +0,0 @@ -local core = require "core" -local common = require "core.common" -local config = require "core.config" -local command = require "core.command" -local style = require "core.style" -local keymap = require "core.keymap" -local translate = require "core.doc.translate" -local RootView = require "core.rootview" -local DocView = require "core.docview" - -config.autocomplete_max_suggestions = 6 - -local autocomplete = {} -autocomplete.map = {} - - -local mt = { __tostring = function(t) return t.text end } - -function autocomplete.add(t) - local items = {} - for text, info in pairs(t.items) do - info = (type(info) == "string") and info - table.insert(items, setmetatable({ text = text, info = info }, mt)) - end - autocomplete.map[t.name] = { files = t.files or ".*", items = items } -end - - -core.add_thread(function() - local cache = setmetatable({}, { __mode = "k" }) - - local function get_symbols(doc) - local i = 1 - local s = {} - while i < #doc.lines do - for sym in doc.lines[i]:gmatch(config.symbol_pattern) do - s[sym] = true - end - i = i + 1 - if i % 100 == 0 then coroutine.yield() end - end - return s - end - - local function cache_is_valid(doc) - local c = cache[doc] - return c and c.last_change_id == doc:get_change_id() - end - - while true do - local symbols = {} - - -- lift all symbols from all docs - for _, doc in ipairs(core.docs) do - -- update the cache if the doc has changed since the last iteration - if not cache_is_valid(doc) then - cache[doc] = { - last_change_id = doc:get_change_id(), - symbols = get_symbols(doc) - } - end - -- update symbol set with doc's symbol set - for sym in pairs(cache[doc].symbols) do - symbols[sym] = true - end - coroutine.yield() - end - - -- update symbols list - autocomplete.add { name = "open-docs", items = symbols } - - -- wait for next scan - local valid = true - while valid do - coroutine.yield(1) - for _, doc in ipairs(core.docs) do - if not cache_is_valid(doc) then - valid = false - end - end - end - - end -end) - - -local partial = "" -local suggestions_idx = 1 -local suggestions = {} -local last_line, last_col - - -local function reset_suggestions() - suggestions_idx = 1 - suggestions = {} -end - - -local function update_suggestions() - local doc = core.active_view.doc - local filename = doc and doc.filename or "" - - -- get all relevant suggestions for given filename - local items = {} - for _, v in pairs(autocomplete.map) do - if common.match_pattern(filename, v.files) then - for _, item in pairs(v.items) do - table.insert(items, item) - end - end - end - - -- fuzzy match, remove duplicates and store - items = common.fuzzy_match(items, partial) - local j = 1 - for i = 1, config.autocomplete_max_suggestions do - suggestions[i] = items[j] - while items[j] and items[i].text == items[j].text do - items[i].info = items[i].info or items[j].info - j = j + 1 - end - end -end - - -local function get_partial_symbol() - local doc = core.active_view.doc - local line2, col2 = doc:get_selection() - local line1, col1 = doc:position_offset(line2, col2, translate.start_of_word) - return doc:get_text(line1, col1, line2, col2) -end - - -local function get_active_view() - if getmetatable(core.active_view) == DocView then - return core.active_view - end -end - - -local function get_suggestions_rect(av) - if #suggestions == 0 then - return 0, 0, 0, 0 - end - - local line, col = av.doc:get_selection() - local x, y = av:get_line_screen_position(line) - x = x + av:get_col_x_offset(line, col - #partial) - y = y + av:get_line_height() + style.padding.y - local font = av:get_font() - local th = font:get_height() - - local max_width = 0 - for _, s in ipairs(suggestions) do - local w = font:get_width(s.text) - if s.info then - w = w + style.font:get_width(s.info) + style.padding.x - end - max_width = math.max(max_width, w) - end - - return - x - style.padding.x, - y - style.padding.y, - max_width + style.padding.x * 2, - #suggestions * (th + style.padding.y) + style.padding.y -end - - -local function draw_suggestions_box(av) - -- draw background rect - local rx, ry, rw, rh = get_suggestions_rect(av) - renderer.draw_rect(rx, ry, rw, rh, style.background3) - - -- draw text - local font = av:get_font() - local lh = font:get_height() + style.padding.y - local y = ry + style.padding.y / 2 - for i, s in ipairs(suggestions) do - local color = (i == suggestions_idx) and style.accent or style.text - common.draw_text(font, color, s.text, "left", rx + style.padding.x, y, rw, lh) - if s.info then - color = (i == suggestions_idx) and style.text or style.dim - common.draw_text(style.font, color, s.info, "right", rx, y, rw - style.padding.x, lh) - end - y = y + lh - end -end - - --- patch event logic into RootView -local on_text_input = RootView.on_text_input -local update = RootView.update -local draw = RootView.draw - - -RootView.on_text_input = function(...) - on_text_input(...) - - local av = get_active_view() - if av then - -- update partial symbol and suggestions - partial = get_partial_symbol() - if #partial >= 3 then - update_suggestions() - last_line, last_col = av.doc:get_selection() - else - reset_suggestions() - end - - -- scroll if rect is out of bounds of view - local _, y, _, h = get_suggestions_rect(av) - local limit = av.position.y + av.size.y - if y + h > limit then - av.scroll.to.y = av.scroll.y + y + h - limit - end - end -end - - -RootView.update = function(...) - update(...) - - local av = get_active_view() - if av then - -- reset suggestions if caret was moved - local line, col = av.doc:get_selection() - if line ~= last_line or col ~= last_col then - reset_suggestions() - end - end -end - - -RootView.draw = function(...) - draw(...) - - local av = get_active_view() - if av then - -- draw suggestions box after everything else - core.root_view:defer_draw(draw_suggestions_box, av) - end -end - - -local function predicate() - return get_active_view() and #suggestions > 0 -end - - -command.add(predicate, { - ["autocomplete:complete"] = function() - local doc = core.active_view.doc - local line, col = doc:get_selection() - local text = suggestions[suggestions_idx].text - doc:insert(line, col, text) - doc:remove(line, col, line, col - #partial) - doc:set_selection(line, col + #text - #partial) - reset_suggestions() - end, - - ["autocomplete:previous"] = function() - suggestions_idx = math.max(suggestions_idx - 1, 1) - end, - - ["autocomplete:next"] = function() - suggestions_idx = math.min(suggestions_idx + 1, #suggestions) - end, - - ["autocomplete:cancel"] = function() - reset_suggestions() - end, -}) - - -keymap.add { - ["tab"] = "autocomplete:complete", - ["up"] = "autocomplete:previous", - ["down"] = "autocomplete:next", - ["escape"] = "autocomplete:cancel", -} - - -return autocomplete diff --git a/tools/lite/data/plugins/autoreload.lua b/tools/lite/data/plugins/autoreload.lua deleted file mode 100644 index a077b6d..0000000 --- a/tools/lite/data/plugins/autoreload.lua +++ /dev/null @@ -1,61 +0,0 @@ -local core = require "core" -local config = require "core.config" -local Doc = require "core.doc" - - -local times = setmetatable({}, { __mode = "k" }) - -local function update_time(doc) - local info = system.get_file_info(doc.filename) - times[doc] = info.modified -end - - -local function reload_doc(doc) - local fp = io.open(doc.filename, "r") - local text = fp:read("*a") - fp:close() - - local sel = { doc:get_selection() } - doc:remove(1, 1, math.huge, math.huge) - doc:insert(1, 1, text:gsub("\r", ""):gsub("\n$", "")) - doc:set_selection(table.unpack(sel)) - - update_time(doc) - doc:clean() - core.log_quiet("Auto-reloaded doc \"%s\"", doc.filename) -end - - -core.add_thread(function() - while true do - -- check all doc modified times - for _, doc in ipairs(core.docs) do - local info = system.get_file_info(doc.filename or "") - if info and times[doc] ~= info.modified then - reload_doc(doc) - end - coroutine.yield() - end - - -- wait for next scan - coroutine.yield(config.project_scan_rate) - end -end) - - --- patch `Doc.save|load` to store modified time -local load = Doc.load -local save = Doc.save - -Doc.load = function(self, ...) - local res = load(self, ...) - update_time(self) - return res -end - -Doc.save = function(self, ...) - local res = save(self, ...) - update_time(self) - return res -end diff --git a/tools/lite/data/plugins/console.lua b/tools/lite/data/plugins/console.lua deleted file mode 100644 index 7a50213..0000000 --- a/tools/lite/data/plugins/console.lua +++ /dev/null @@ -1,385 +0,0 @@ -local core = require "core" -local keymap = require "core.keymap" -local command = require "core.command" -local common = require "core.common" -local config = require "core.config" -local style = require "core.style" -local View = require "core.view" - -config.console_size = 250 * SCALE -config.max_console_lines = 200 -config.autoscroll_console = true - -local files = { - script = core.temp_filename(PLATFORM == "Windows" and ".bat"), - script2 = core.temp_filename(PLATFORM == "Windows" and ".bat"), - output = core.temp_filename(), - complete = core.temp_filename(), -} - -local console = {} - -local views = {} -local pending_threads = {} -local thread_active = false -local output = nil -local output_id = 0 -local visible = false - -function console.clear() - output = { { text = "", time = 0 } } -end - - -local function read_file(filename, offset) - local fp = io.open(filename, "rb") - fp:seek("set", offset or 0) - local res = fp:read("*a") - fp:close() - return res -end - - -local function write_file(filename, text) - local fp = io.open(filename, "w") - fp:write(text) - fp:close() -end - - -local function lines(text) - return (text .. "\n"):gmatch("(.-)\n") -end - - -local function push_output(str, opt) - local first = true - for line in lines(str) do - if first then - line = table.remove(output).text .. line - end - line = line:gsub("\x1b%[[%d;]+m", "") -- strip ANSI colors - table.insert(output, { - text = line, - time = os.time(), - icon = line:find(opt.error_pattern) and "!" - or line:find(opt.warning_pattern) and "i", - file_pattern = opt.file_pattern, - }) - if #output > config.max_console_lines then - table.remove(output, 1) - for view in pairs(views) do - view:on_line_removed() - end - end - first = false - end - output_id = output_id + 1 - core.redraw = true -end - - -local function init_opt(opt) - local res = { - command = "", - file_pattern = "[^?:%s]+%.[^?:%s]+", - error_pattern = "error", - warning_pattern = "warning", - on_complete = function() end, - } - for k, v in pairs(res) do - res[k] = opt[k] or v - end - return res -end - - -function console.run(opt) - opt = init_opt(opt) - - local function thread() - -- init script file(s) - if PLATFORM == "Windows" then - write_file(files.script, opt.command .. "\n") - write_file(files.script2, string.format([[ - @echo off - call %q >%q 2>&1 - echo "" >%q - exit - ]], files.script, files.output, files.complete)) - system.exec(string.format("call %q", files.script2)) - else - write_file(files.script, string.format([[ - %s - touch %q - ]], opt.command, files.complete)) - system.exec(string.format("bash %q >%q 2>&1", files.script, files.output)) - end - - -- checks output file for change and reads - local last_size = 0 - local function check_output_file() - if PLATFORM == "Windows" then - local fp = io.open(files.output) - if fp then fp:close() end - end - local info = system.get_file_info(files.output) - if info and info.size > last_size then - local text = read_file(files.output, last_size) - push_output(text, opt) - last_size = info.size - end - end - - -- read output file until we get a file indicating completion - while not system.get_file_info(files.complete) do - check_output_file() - coroutine.yield(0.1) - end - check_output_file() - if output[#output].text ~= "" then - push_output("\n", opt) - end - push_output("!DIVIDER\n", opt) - - -- clean up and finish - for _, file in pairs(files) do - os.remove(file) - end - opt.on_complete() - - -- handle pending thread - local pending = table.remove(pending_threads, 1) - if pending then - core.add_thread(pending) - else - thread_active = false - end - end - - -- push/init thread - if thread_active then - table.insert(pending_threads, thread) - else - core.add_thread(thread) - thread_active = true - end - - -- make sure static console is visible if it's the only ConsoleView - local count = 0 - for _ in pairs(views) do count = count + 1 end - if count == 1 then visible = true end -end - - - -local ConsoleView = View:extend() - -function ConsoleView:new() - ConsoleView.super.new(self) - self.scrollable = true - self.hovered_idx = -1 - views[self] = true -end - - -function ConsoleView:try_close(...) - ConsoleView.super.try_close(self, ...) - views[self] = nil -end - - -function ConsoleView:get_name() - return "Console" -end - - -function ConsoleView:get_line_height() - return style.code_font:get_height() * config.line_height -end - - -function ConsoleView:get_line_count() - return #output - (output[#output].text == "" and 1 or 0) -end - - -function ConsoleView:get_scrollable_size() - return self:get_line_count() * self:get_line_height() + style.padding.y * 2 -end - - -function ConsoleView:get_visible_line_range() - local lh = self:get_line_height() - local min = math.max(1, math.floor(self.scroll.y / lh)) - return min, min + math.floor(self.size.y / lh) + 1 -end - - -function ConsoleView:on_mouse_moved(mx, my, ...) - ConsoleView.super.on_mouse_moved(self, mx, my, ...) - self.hovered_idx = 0 - for i, item, x,y,w,h in self:each_visible_line() do - if mx >= x and my >= y and mx < x + w and my < y + h then - if item.text:find(item.file_pattern) then - self.hovered_idx = i - end - break - end - end -end - - -local function resolve_file(name) - if system.get_file_info(name) then - return name - end - local filenames = {} - for _, f in ipairs(core.project_files) do - table.insert(filenames, f.filename) - end - local t = common.fuzzy_match(filenames, name) - return t[1] -end - - -function ConsoleView:on_line_removed() - local diff = self:get_line_height() - self.scroll.y = self.scroll.y - diff - self.scroll.to.y = self.scroll.to.y - diff -end - - -function ConsoleView:on_mouse_pressed(...) - local caught = ConsoleView.super.on_mouse_pressed(self, ...) - if caught then - return - end - local item = output[self.hovered_idx] - if item then - local file, line, col = item.text:match(item.file_pattern) - local resolved_file = resolve_file(file) - if not resolved_file then - core.error("Couldn't resolve file \"%s\"", file) - return - end - core.try(function() - core.set_active_view(core.last_active_view) - local dv = core.root_view:open_doc(core.open_doc(resolved_file)) - if line then - dv.doc:set_selection(line, col or 0) - dv:scroll_to_line(line, false, true) - end - end) - end -end - - -function ConsoleView:each_visible_line() - return coroutine.wrap(function() - local x, y = self:get_content_offset() - local lh = self:get_line_height() - local min, max = self:get_visible_line_range() - y = y + lh * (min - 1) + style.padding.y - max = math.min(max, self:get_line_count()) - - for i = min, max do - local item = output[i] - if not item then break end - coroutine.yield(i, item, x, y, self.size.x, lh) - y = y + lh - end - end) -end - - -function ConsoleView:update(...) - if self.last_output_id ~= output_id then - if config.autoscroll_console then - self.scroll.to.y = self:get_scrollable_size() - end - self.last_output_id = output_id - end - ConsoleView.super.update(self, ...) -end - - -function ConsoleView:draw() - self:draw_background(style.background) - local icon_w = style.icon_font:get_width("!") - - for i, item, x, y, w, h in self:each_visible_line() do - local tx = x + style.padding.x - local time = os.date("%H:%M:%S", item.time) - local color = style.text - if self.hovered_idx == i then - color = style.accent - renderer.draw_rect(x, y, w, h, style.line_highlight) - end - if item.text == "!DIVIDER" then - local w = style.font:get_width(time) - renderer.draw_rect(tx, y + h / 2, w, math.ceil(SCALE * 1), style.dim) - else - tx = common.draw_text(style.font, style.dim, time, "left", tx, y, w, h) - tx = tx + style.padding.x - if item.icon then - common.draw_text(style.icon_font, color, item.icon, "left", tx, y, w, h) - end - tx = tx + icon_w + style.padding.x - common.draw_text(style.code_font, color, item.text, "left", tx, y, w, h) - end - end - - self:draw_scrollbar(self) -end - - --- init static bottom-of-screen console -local view = ConsoleView() -local node = core.root_view:get_active_node() -node:split("down", view, true) - -function view:update(...) - local dest = visible and config.console_size or 0 - self:move_towards(self.size, "y", dest) - ConsoleView.update(self, ...) -end - - -local last_command = "" - -command.add(nil, { - ["console:reset-output"] = function() - output = { { text = "", time = 0 } } - end, - - ["console:open-console"] = function() - local node = core.root_view:get_active_node() - node:add_view(ConsoleView()) - end, - - ["console:toggle"] = function() - visible = not visible - end, - - ["console:run"] = function() - core.command_view:set_text(last_command, true) - core.command_view:enter("Run Console Command", function(cmd) - console.run { command = cmd } - last_command = cmd - end) - end -}) - -keymap.add { - ["ctrl+."] = "console:toggle", - ["ctrl+shift+."] = "console:run", -} - --- for `workspace` plugin: -package.loaded["plugins.console.view"] = ConsoleView - -console.clear() - - -return console \ No newline at end of file diff --git a/tools/lite/data/plugins/language_c.lua b/tools/lite/data/plugins/language_c.lua deleted file mode 100644 index 8e8ee98..0000000 --- a/tools/lite/data/plugins/language_c.lua +++ /dev/null @@ -1,59 +0,0 @@ -local syntax = require "core.syntax" - -syntax.add { - files = { "%.c$", "%.h$", "%.inl$", "%.cpp$", "%.hpp$" }, - comment = "//", - patterns = { - { pattern = "//.-\n", type = "comment" }, - { pattern = { "/%*", "%*/" }, type = "comment" }, - { pattern = { "#", "[^\\]\n" }, type = "comment" }, - { pattern = { '"', '"', '\\' }, type = "string" }, - { pattern = { "'", "'", '\\' }, type = "string" }, - { pattern = "-?0x%x+", type = "number" }, - { pattern = "-?%d+[%d%.eE]*f?", type = "number" }, - { pattern = "-?%.?%d+f?", type = "number" }, - { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, - { pattern = "[%a_][%w_]*%f[(]", type = "function" }, - { pattern = "[%a_][%w_]*", type = "symbol" }, - }, - symbols = { - ["if"] = "keyword", - ["then"] = "keyword", - ["else"] = "keyword", - ["elseif"] = "keyword", - ["do"] = "keyword", - ["while"] = "keyword", - ["for"] = "keyword", - ["break"] = "keyword", - ["continue"] = "keyword", - ["return"] = "keyword", - ["goto"] = "keyword", - ["struct"] = "keyword", - ["union"] = "keyword", - ["typedef"] = "keyword", - ["enum"] = "keyword", - ["extern"] = "keyword", - ["static"] = "keyword", - ["volatile"] = "keyword", - ["const"] = "keyword", - ["inline"] = "keyword", - ["switch"] = "keyword", - ["case"] = "keyword", - ["default"] = "keyword", - ["auto"] = "keyword", - ["const"] = "keyword", - ["void"] = "keyword", - ["int"] = "keyword2", - ["short"] = "keyword2", - ["long"] = "keyword2", - ["float"] = "keyword2", - ["double"] = "keyword2", - ["char"] = "keyword2", - ["unsigned"] = "keyword2", - ["bool"] = "keyword2", - ["true"] = "literal", - ["false"] = "literal", - ["NULL"] = "literal", - }, -} - diff --git a/tools/lite/data/plugins/language_css.lua b/tools/lite/data/plugins/language_css.lua deleted file mode 100644 index 021c5d3..0000000 --- a/tools/lite/data/plugins/language_css.lua +++ /dev/null @@ -1,23 +0,0 @@ -local syntax = require "core.syntax" - -syntax.add { - files = { "%.css$" }, - patterns = { - { pattern = "\\.", type = "normal" }, - { pattern = "//.-\n", type = "comment" }, - { pattern = { "/%*", "%*/" }, type = "comment" }, - { pattern = { '"', '"', '\\' }, type = "string" }, - { pattern = { "'", "'", '\\' }, type = "string" }, - { pattern = "[%a][%w-]*%s*%f[:]", type = "keyword" }, - { pattern = "#%x+", type = "string" }, - { pattern = "-?%d+[%d%.]*p[xt]", type = "number" }, - { pattern = "-?%d+[%d%.]*deg", type = "number" }, - { pattern = "-?%d+[%d%.]*", type = "number" }, - { pattern = "[%a_][%w_]*", type = "symbol" }, - { pattern = "#[%a][%w_-]*", type = "keyword2" }, - { pattern = "@[%a][%w_-]*", type = "keyword2" }, - { pattern = "%.[%a][%w_-]*", type = "keyword2" }, - { pattern = "[{}:]", type = "operator" }, - }, - symbols = {}, -} diff --git a/tools/lite/data/plugins/language_js.lua b/tools/lite/data/plugins/language_js.lua deleted file mode 100644 index cf1b124..0000000 --- a/tools/lite/data/plugins/language_js.lua +++ /dev/null @@ -1,67 +0,0 @@ -local syntax = require "core.syntax" - -syntax.add { - files = { "%.js$", "%.json$", "%.cson$" }, - comment = "//", - patterns = { - { pattern = "//.-\n", type = "comment" }, - { pattern = { "/%*", "%*/" }, type = "comment" }, - { pattern = { '"', '"', '\\' }, type = "string" }, - { pattern = { "'", "'", '\\' }, type = "string" }, - { pattern = { "`", "`", '\\' }, type = "string" }, - { pattern = "0x[%da-fA-F]+", type = "number" }, - { pattern = "-?%d+[%d%.eE]*", type = "number" }, - { pattern = "-?%.?%d+", type = "number" }, - { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, - { pattern = "[%a_][%w_]*%f[(]", type = "function" }, - { pattern = "[%a_][%w_]*", type = "symbol" }, - }, - symbols = { - ["async"] = "keyword", - ["await"] = "keyword", - ["break"] = "keyword", - ["case"] = "keyword", - ["catch"] = "keyword", - ["class"] = "keyword", - ["const"] = "keyword", - ["continue"] = "keyword", - ["debugger"] = "keyword", - ["default"] = "keyword", - ["delete"] = "keyword", - ["do"] = "keyword", - ["else"] = "keyword", - ["export"] = "keyword", - ["extends"] = "keyword", - ["finally"] = "keyword", - ["for"] = "keyword", - ["function"] = "keyword", - ["get"] = "keyword", - ["if"] = "keyword", - ["import"] = "keyword", - ["in"] = "keyword", - ["instanceof"] = "keyword", - ["let"] = "keyword", - ["new"] = "keyword", - ["return"] = "keyword", - ["set"] = "keyword", - ["static"] = "keyword", - ["super"] = "keyword", - ["switch"] = "keyword", - ["throw"] = "keyword", - ["try"] = "keyword", - ["typeof"] = "keyword", - ["var"] = "keyword", - ["void"] = "keyword", - ["while"] = "keyword", - ["with"] = "keyword", - ["yield"] = "keyword", - ["true"] = "literal", - ["false"] = "literal", - ["null"] = "literal", - ["undefined"] = "literal", - ["arguments"] = "keyword2", - ["Infinity"] = "keyword2", - ["NaN"] = "keyword2", - ["this"] = "keyword2", - }, -} diff --git a/tools/lite/data/plugins/language_lua.lua b/tools/lite/data/plugins/language_lua.lua deleted file mode 100644 index 915d273..0000000 --- a/tools/lite/data/plugins/language_lua.lua +++ /dev/null @@ -1,50 +0,0 @@ -local syntax = require "core.syntax" - -syntax.add { - files = "%.lua$", - headers = "^#!.*[ /]lua", - comment = "--", - patterns = { - { pattern = { '"', '"', '\\' }, type = "string" }, - { pattern = { "'", "'", '\\' }, type = "string" }, - { pattern = { "%[%[", "%]%]" }, type = "string" }, - { pattern = { "%-%-%[%[", "%]%]"}, type = "comment" }, - { pattern = "%-%-.-\n", type = "comment" }, - { pattern = "-?0x%x+", type = "number" }, - { pattern = "-?%d+[%d%.eE]*", type = "number" }, - { pattern = "-?%.?%d+", type = "number" }, - { pattern = "<%a+>", type = "keyword2" }, - { pattern = "%.%.%.?", type = "operator" }, - { pattern = "[<>~=]=", type = "operator" }, - { pattern = "[%+%-=/%*%^%%#<>]", type = "operator" }, - { pattern = "[%a_][%w_]*%s*%f[(\"{]", type = "function" }, - { pattern = "[%a_][%w_]*", type = "symbol" }, - { pattern = "::[%a_][%w_]*::", type = "function" }, - }, - symbols = { - ["if"] = "keyword", - ["then"] = "keyword", - ["else"] = "keyword", - ["elseif"] = "keyword", - ["end"] = "keyword", - ["do"] = "keyword", - ["function"] = "keyword", - ["repeat"] = "keyword", - ["until"] = "keyword", - ["while"] = "keyword", - ["for"] = "keyword", - ["break"] = "keyword", - ["return"] = "keyword", - ["local"] = "keyword", - ["in"] = "keyword", - ["not"] = "keyword", - ["and"] = "keyword", - ["or"] = "keyword", - ["goto"] = "keyword", - ["self"] = "keyword2", - ["true"] = "literal", - ["false"] = "literal", - ["nil"] = "literal", - }, -} - diff --git a/tools/lite/data/plugins/language_md.lua b/tools/lite/data/plugins/language_md.lua deleted file mode 100644 index 9f0f14e..0000000 --- a/tools/lite/data/plugins/language_md.lua +++ /dev/null @@ -1,21 +0,0 @@ -local syntax = require "core.syntax" - -syntax.add { - files = { "%.md$", "%.markdown$" }, - patterns = { - { pattern = "\\.", type = "normal" }, - { pattern = { "" }, type = "comment" }, - { pattern = { "```", "```" }, type = "string" }, - { pattern = { "``", "``", "\\" }, type = "string" }, - { pattern = { "`", "`", "\\" }, type = "string" }, - { pattern = { "~~", "~~", "\\" }, type = "keyword2" }, - { pattern = "%-%-%-+", type = "comment" }, - { pattern = "%*%s+", type = "operator" }, - { pattern = { "%*", "[%*\n]", "\\" }, type = "operator" }, - { pattern = { "%_", "[%_\n]", "\\" }, type = "keyword2" }, - { pattern = "#.-\n", type = "keyword" }, - { pattern = "!?%[.-%]%(.-%)", type = "function" }, - { pattern = "https?://%S+", type = "function" }, - }, - symbols = { }, -} diff --git a/tools/lite/data/plugins/language_python.lua b/tools/lite/data/plugins/language_python.lua deleted file mode 100644 index 4a6ada3..0000000 --- a/tools/lite/data/plugins/language_python.lua +++ /dev/null @@ -1,55 +0,0 @@ -local syntax = require "core.syntax" - -syntax.add { - files = "%.py$", - headers = "^#!.*[ /]python", - comment = "#", - patterns = { - { pattern = { "#", "\n" }, type = "comment" }, - { pattern = { '[ruU]?"', '"', '\\' }, type = "string" }, - { pattern = { "[ruU]?'", "'", '\\' }, type = "string" }, - { pattern = { '"""', '"""' }, type = "string" }, - { pattern = "0x[%da-fA-F]+", type = "number" }, - { pattern = "-?%d+[%d%.eE]*", type = "number" }, - { pattern = "-?%.?%d+", type = "number" }, - { pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" }, - { pattern = "[%a_][%w_]*%f[(]", type = "function" }, - { pattern = "[%a_][%w_]*", type = "symbol" }, - }, - symbols = { - ["class"] = "keyword", - ["finally"] = "keyword", - ["is"] = "keyword", - ["return"] = "keyword", - ["continue"] = "keyword", - ["for"] = "keyword", - ["lambda"] = "keyword", - ["try"] = "keyword", - ["def"] = "keyword", - ["from"] = "keyword", - ["nonlocal"] = "keyword", - ["while"] = "keyword", - ["and"] = "keyword", - ["global"] = "keyword", - ["not"] = "keyword", - ["with"] = "keyword", - ["as"] = "keyword", - ["elif"] = "keyword", - ["if"] = "keyword", - ["or"] = "keyword", - ["else"] = "keyword", - ["import"] = "keyword", - ["pass"] = "keyword", - ["break"] = "keyword", - ["except"] = "keyword", - ["in"] = "keyword", - ["del"] = "keyword", - ["raise"] = "keyword", - ["yield"] = "keyword", - ["assert"] = "keyword", - ["self"] = "keyword2", - ["None"] = "literal", - ["True"] = "literal", - ["False"] = "literal", - } -} diff --git a/tools/lite/data/plugins/language_xml.lua b/tools/lite/data/plugins/language_xml.lua deleted file mode 100644 index 5240bdc..0000000 --- a/tools/lite/data/plugins/language_xml.lua +++ /dev/null @@ -1,21 +0,0 @@ -local syntax = require "core.syntax" - -syntax.add { - files = { "%.xml$", "%.html?$" }, - headers = "<%?xml", - patterns = { - { pattern = { "" }, type = "comment" }, - { pattern = { '%f[^>][^<]', '%f[<]' }, type = "normal" }, - { pattern = { '"', '"', '\\' }, type = "string" }, - { pattern = { "'", "'", '\\' }, type = "string" }, - { pattern = "0x[%da-fA-F]+", type = "number" }, - { pattern = "-?%d+[%d%.]*f?", type = "number" }, - { pattern = "-?%.?%d+f?", type = "number" }, - { pattern = "%f[^<]![%a_][%w_]*", type = "keyword2" }, - { pattern = "%f[^<][%a_][%w_]*", type = "function" }, - { pattern = "%f[^<]/[%a_][%w_]*", type = "function" }, - { pattern = "[%a_][%w_]*", type = "keyword" }, - { pattern = "[/<>=]", type = "operator" }, - }, - symbols = {}, -} diff --git a/tools/lite/data/plugins/macro.lua b/tools/lite/data/plugins/macro.lua deleted file mode 100644 index 3458977..0000000 --- a/tools/lite/data/plugins/macro.lua +++ /dev/null @@ -1,69 +0,0 @@ -local core = require "core" -local command = require "core.command" -local keymap = require "core.keymap" - -local handled_events = { - ["keypressed"] = true, - ["keyreleased"] = true, - ["textinput"] = true, -} - -local state = "stopped" -local event_buffer = {} -local modkeys = {} - -local on_event = core.on_event - -core.on_event = function(type, ...) - local res = on_event(type, ...) - if state == "recording" and handled_events[type] then - table.insert(event_buffer, { type, ... }) - end - return res -end - - -local function clone(t) - local res = {} - for k, v in pairs(t) do res[k] = v end - return res -end - - -local function predicate() - return state ~= "playing" -end - - -command.add(predicate, { - ["macro:toggle-record"] = function() - if state == "stopped" then - state = "recording" - event_buffer = {} - modkeys = clone(keymap.modkeys) - core.log("Recording macro...") - else - state = "stopped" - core.log("Stopped recording macro (%d events)", #event_buffer) - end - end, - - ["macro:play"] = function() - state = "playing" - core.log("Playing macro... (%d events)", #event_buffer) - local mk = keymap.modkeys - keymap.modkeys = clone(modkeys) - for _, ev in ipairs(event_buffer) do - on_event(table.unpack(ev)) - core.root_view:update() - end - keymap.modkeys = mk - state = "stopped" - end, -}) - - -keymap.add { - ["ctrl+shift+;"] = "macro:toggle-record", - ["ctrl+;"] = "macro:play", -} diff --git a/tools/lite/data/plugins/projectsearch.lua b/tools/lite/data/plugins/projectsearch.lua deleted file mode 100644 index 884e66a..0000000 --- a/tools/lite/data/plugins/projectsearch.lua +++ /dev/null @@ -1,271 +0,0 @@ -local core = require "core" -local common = require "core.common" -local keymap = require "core.keymap" -local command = require "core.command" -local style = require "core.style" -local View = require "core.view" - - -local ResultsView = View:extend() - - -function ResultsView:new(text, fn) - ResultsView.super.new(self) - self.scrollable = true - self.brightness = 0 - self:begin_search(text, fn) -end - - -function ResultsView:get_name() - return "Search Results" -end - - -local function find_all_matches_in_file(t, filename, fn) - local fp = io.open(filename) - if not fp then return t end - local n = 1 - for line in fp:lines() do - local s = fn(line) - if s then - table.insert(t, { file = filename, text = line, line = n, col = s }) - core.redraw = true - end - if n % 100 == 0 then coroutine.yield() end - n = n + 1 - core.redraw = true - end - fp:close() -end - - -function ResultsView:begin_search(text, fn) - self.search_args = { text, fn } - self.results = {} - self.last_file_idx = 1 - self.query = text - self.searching = true - self.selected_idx = 0 - - core.add_thread(function() - for i, file in ipairs(core.project_files) do - if file.type == "file" then - find_all_matches_in_file(self.results, file.filename, fn) - end - self.last_file_idx = i - end - self.searching = false - self.brightness = 100 - core.redraw = true - end, self.results) - - self.scroll.to.y = 0 -end - - -function ResultsView:refresh() - self:begin_search(table.unpack(self.search_args)) -end - - -function ResultsView:on_mouse_moved(mx, my, ...) - ResultsView.super.on_mouse_moved(self, mx, my, ...) - self.selected_idx = 0 - for i, item, x,y,w,h in self:each_visible_result() do - if mx >= x and my >= y and mx < x + w and my < y + h then - self.selected_idx = i - break - end - end -end - - -function ResultsView:on_mouse_pressed(...) - local caught = ResultsView.super.on_mouse_pressed(self, ...) - if not caught then - self:open_selected_result() - end -end - - -function ResultsView:open_selected_result() - local res = self.results[self.selected_idx] - if not res then - return - end - core.try(function() - local dv = core.root_view:open_doc(core.open_doc(res.file)) - core.root_view.root_node:update_layout() - dv.doc:set_selection(res.line, res.col) - dv:scroll_to_line(res.line, false, true) - end) -end - - -function ResultsView:update() - self:move_towards("brightness", 0, 0.1) - ResultsView.super.update(self) -end - - -function ResultsView:get_results_yoffset() - return style.font:get_height() + style.padding.y * 3 -end - - -function ResultsView:get_line_height() - return style.padding.y + style.font:get_height() -end - - -function ResultsView:get_scrollable_size() - return self:get_results_yoffset() + #self.results * self:get_line_height() -end - - -function ResultsView:get_visible_results_range() - local lh = self:get_line_height() - local oy = self:get_results_yoffset() - local min = math.max(1, math.floor((self.scroll.y - oy) / lh)) - return min, min + math.floor(self.size.y / lh) + 1 -end - - -function ResultsView:each_visible_result() - return coroutine.wrap(function() - local lh = self:get_line_height() - local x, y = self:get_content_offset() - local min, max = self:get_visible_results_range() - y = y + self:get_results_yoffset() + lh * (min - 1) - for i = min, max do - local item = self.results[i] - if not item then break end - coroutine.yield(i, item, x, y, self.size.x, lh) - y = y + lh - end - end) -end - - -function ResultsView:scroll_to_make_selected_visible() - local h = self:get_line_height() - local y = self:get_results_yoffset() + h * (self.selected_idx - 1) - self.scroll.to.y = math.min(self.scroll.to.y, y) - self.scroll.to.y = math.max(self.scroll.to.y, y + h - self.size.y) -end - - -function ResultsView:draw() - self:draw_background(style.background) - - -- status - local ox, oy = self:get_content_offset() - local x, y = ox + style.padding.x, oy + style.padding.y - local per = self.last_file_idx / #core.project_files - local text - if self.searching then - text = string.format("Searching %d%% (%d of %d files, %d matches) for %q...", - per * 100, self.last_file_idx, #core.project_files, - #self.results, self.query) - else - text = string.format("Found %d matches for %q", - #self.results, self.query) - end - local color = common.lerp(style.text, style.accent, self.brightness / 100) - renderer.draw_text(style.font, text, x, y, color) - - -- horizontal line - local yoffset = self:get_results_yoffset() - local x = ox + style.padding.x - local w = self.size.x - style.padding.x * 2 - local h = style.divider_size - local color = common.lerp(style.dim, style.text, self.brightness / 100) - renderer.draw_rect(x, oy + yoffset - style.padding.y, w, h, color) - if self.searching then - renderer.draw_rect(x, oy + yoffset - style.padding.y, w * per, h, style.text) - end - - -- results - local y1, y2 = self.position.y, self.position.y + self.size.y - for i, item, x,y,w,h in self:each_visible_result() do - local color = style.text - if i == self.selected_idx then - color = style.accent - renderer.draw_rect(x, y, w, h, style.line_highlight) - end - x = x + style.padding.x - local text = string.format("%s at line %d (col %d): ", item.file, item.line, item.col) - x = common.draw_text(style.font, style.dim, text, "left", x, y, w, h) - x = common.draw_text(style.code_font, color, item.text, "left", x, y, w, h) - end - - self:draw_scrollbar() -end - - -local function begin_search(text, fn) - if text == "" then - core.error("Expected non-empty string") - return - end - local rv = ResultsView(text, fn) - core.root_view:get_active_node():add_view(rv) -end - - -command.add(nil, { - ["project-search:find"] = function() - core.command_view:enter("Find Text In Project", function(text) - text = text:lower() - begin_search(text, function(line_text) - return line_text:lower():find(text, nil, true) - end) - end) - end, - - ["project-search:find-pattern"] = function() - core.command_view:enter("Find Pattern In Project", function(text) - begin_search(text, function(line_text) return line_text:find(text) end) - end) - end, - - ["project-search:fuzzy-find"] = function() - core.command_view:enter("Fuzzy Find Text In Project", function(text) - begin_search(text, function(line_text) - return common.fuzzy_match(line_text, text) and 1 - end) - end) - end, -}) - - -command.add(ResultsView, { - ["project-search:select-previous"] = function() - local view = core.active_view - view.selected_idx = math.max(view.selected_idx - 1, 1) - view:scroll_to_make_selected_visible() - end, - - ["project-search:select-next"] = function() - local view = core.active_view - view.selected_idx = math.min(view.selected_idx + 1, #view.results) - view:scroll_to_make_selected_visible() - end, - - ["project-search:open-selected"] = function() - core.active_view:open_selected_result() - end, - - ["project-search:refresh"] = function() - core.active_view:refresh() - end, -}) - -keymap.add { - ["f5"] = "project-search:refresh", - ["ctrl+shift+f"] = "project-search:find", - ["up"] = "project-search:select-previous", - ["down"] = "project-search:select-next", - ["return"] = "project-search:open-selected", -} diff --git a/tools/lite/data/plugins/quote.lua b/tools/lite/data/plugins/quote.lua deleted file mode 100644 index b17407d..0000000 --- a/tools/lite/data/plugins/quote.lua +++ /dev/null @@ -1,30 +0,0 @@ -local core = require "core" -local command = require "core.command" -local keymap = require "core.keymap" - - -local escapes = { - ["\\"] = "\\\\", - ["\""] = "\\\"", - ["\n"] = "\\n", - ["\r"] = "\\r", - ["\t"] = "\\t", - ["\b"] = "\\b", -} - -local function replace(chr) - return escapes[chr] or string.format("\\x%02x", chr:byte()) -end - - -command.add("core.docview", { - ["quote:quote"] = function() - core.active_view.doc:replace(function(text) - return '"' .. text:gsub("[\0-\31\\\"]", replace) .. '"' - end) - end, -}) - -keymap.add { - ["ctrl+'"] = "quote:quote", -} diff --git a/tools/lite/data/plugins/reflow.lua b/tools/lite/data/plugins/reflow.lua deleted file mode 100644 index 95090a6..0000000 --- a/tools/lite/data/plugins/reflow.lua +++ /dev/null @@ -1,63 +0,0 @@ -local core = require "core" -local config = require "core.config" -local command = require "core.command" -local keymap = require "core.keymap" - - -local function wordwrap_text(text, limit) - local t = {} - local n = 0 - - for word in text:gmatch("%S+") do - if n + #word > limit then - table.insert(t, "\n") - n = 0 - elseif #t > 0 then - table.insert(t, " ") - end - table.insert(t, word) - n = n + #word + 1 - end - - return table.concat(t) -end - - -command.add("core.docview", { - ["reflow:reflow"] = function() - local doc = core.active_view.doc - doc:replace(function(text) - local prefix_set = "[^%w\n%[%](){}`'\"]*" - - -- get line prefix and trailing whitespace - local prefix1 = text:match("^\n*" .. prefix_set) - local prefix2 = text:match("\n(" .. prefix_set .. ")", #prefix1+1) - local trailing = text:match("%s*$") - if not prefix2 or prefix2 == "" then - prefix2 = prefix1 - end - - -- strip all line prefixes and trailing whitespace - text = text:sub(#prefix1+1, -#trailing - 1):gsub("\n" .. prefix_set, "\n") - - -- split into blocks, wordwrap and join - local line_limit = config.line_limit - #prefix1 - local blocks = {} - text = text:gsub("\n\n", "\0") - for block in text:gmatch("%Z+") do - table.insert(blocks, wordwrap_text(block, line_limit)) - end - text = table.concat(blocks, "\n\n") - - -- add prefix to start of lines - text = prefix1 .. text:gsub("\n", "\n" .. prefix2) .. trailing - - return text - end) - end, -}) - - -keymap.add { - ["ctrl+shift+q"] = "reflow:reflow" -} diff --git a/tools/lite/data/plugins/tabularize.lua b/tools/lite/data/plugins/tabularize.lua deleted file mode 100644 index f4dda1f..0000000 --- a/tools/lite/data/plugins/tabularize.lua +++ /dev/null @@ -1,60 +0,0 @@ -local core = require "core" -local command = require "core.command" -local translate = require "core.doc.translate" - - -local function gmatch_to_array(text, ptn) - local res = {} - for x in text:gmatch(ptn) do - table.insert(res, x) - end - return res -end - - -local function tabularize_lines(lines, delim) - local rows = {} - local cols = {} - - -- split lines at delimiters and get maximum width of columns - local ptn = "[^" .. delim:sub(1,1):gsub("%W", "%%%1") .. "]+" - for i, line in ipairs(lines) do - rows[i] = gmatch_to_array(line, ptn) - for j, col in ipairs(rows[i]) do - cols[j] = math.max(#col, cols[j] or 0) - end - end - - -- pad columns with space - for _, row in ipairs(rows) do - for i = 1, #row - 1 do - row[i] = row[i] .. string.rep(" ", cols[i] - #row[i]) - end - end - - -- write columns back to lines array - for i, line in ipairs(lines) do - lines[i] = table.concat(rows[i], delim) - end -end - - -command.add("core.docview", { - ["tabularize:tabularize"] = function() - core.command_view:enter("Tabularize On Delimiter", function(delim) - if delim == "" then delim = " " end - - local doc = core.active_view.doc - local line1, col1, line2, col2, swap = doc:get_selection(true) - line1, col1 = doc:position_offset(line1, col1, translate.start_of_line) - line2, col2 = doc:position_offset(line2, col2, translate.end_of_line) - doc:set_selection(line1, col1, line2, col2, swap) - - doc:replace(function(text) - local lines = gmatch_to_array(text, "[^\n]*\n?") - tabularize_lines(lines, delim) - return table.concat(lines) - end) - end) - end, -}) diff --git a/tools/lite/data/plugins/treeview.lua b/tools/lite/data/plugins/treeview.lua deleted file mode 100644 index 8aa53ff..0000000 --- a/tools/lite/data/plugins/treeview.lua +++ /dev/null @@ -1,197 +0,0 @@ -local core = require "core" -local common = require "core.common" -local command = require "core.command" -local config = require "core.config" -local keymap = require "core.keymap" -local style = require "core.style" -local View = require "core.view" - -config.treeview_size = 200 * SCALE - -local function get_depth(filename) - local n = 0 - for sep in filename:gmatch("[\\/]") do - n = n + 1 - end - return n -end - - -local TreeView = View:extend() - -function TreeView:new() - TreeView.super.new(self) - self.scrollable = true - self.visible = true - self.init_size = true - self.cache = {} -end - - -function TreeView:get_cached(item) - local t = self.cache[item.filename] - if not t then - t = {} - t.filename = item.filename - t.abs_filename = system.absolute_path(item.filename) - t.name = t.filename:match("[^\\/]+$") - t.depth = get_depth(t.filename) - t.type = item.type - self.cache[t.filename] = t - end - return t -end - - -function TreeView:get_name() - return "Project" -end - - -function TreeView:get_item_height() - return style.font:get_height() + style.padding.y -end - - -function TreeView:check_cache() - -- invalidate cache's skip values if project_files has changed - if core.project_files ~= self.last_project_files then - for _, v in pairs(self.cache) do - v.skip = nil - end - self.last_project_files = core.project_files - end -end - - -function TreeView:each_item() - return coroutine.wrap(function() - self:check_cache() - local ox, oy = self:get_content_offset() - local y = oy + style.padding.y - local w = self.size.x - local h = self:get_item_height() - - local i = 1 - while i <= #core.project_files do - local item = core.project_files[i] - local cached = self:get_cached(item) - - coroutine.yield(cached, ox, y, w, h) - y = y + h - i = i + 1 - - if not cached.expanded then - if cached.skip then - i = cached.skip - else - local depth = cached.depth - while i <= #core.project_files do - local filename = core.project_files[i].filename - if get_depth(filename) <= depth then break end - i = i + 1 - end - cached.skip = i - end - end - end - end) -end - - -function TreeView:on_mouse_moved(px, py) - self.hovered_item = nil - for item, x,y,w,h in self:each_item() do - if px > x and py > y and px <= x + w and py <= y + h then - self.hovered_item = item - break - end - end -end - - -function TreeView:on_mouse_pressed(button, x, y) - if not self.hovered_item then - return - elseif self.hovered_item.type == "dir" then - self.hovered_item.expanded = not self.hovered_item.expanded - else - core.try(function() - core.root_view:open_doc(core.open_doc(self.hovered_item.filename)) - end) - end -end - - -function TreeView:update() - -- update width - local dest = self.visible and config.treeview_size or 0 - if self.init_size then - self.size.x = dest - self.init_size = false - else - self:move_towards(self.size, "x", dest) - end - - TreeView.super.update(self) -end - - -function TreeView:draw() - self:draw_background(style.background2) - - local icon_width = style.icon_font:get_width("D") - local spacing = style.font:get_width(" ") * 2 - - local doc = core.active_view.doc - local active_filename = doc and system.absolute_path(doc.filename or "") - - for item, x,y,w,h in self:each_item() do - local color = style.text - - -- highlight active_view doc - if item.abs_filename == active_filename then - color = style.accent - end - - -- hovered item background - if item == self.hovered_item then - renderer.draw_rect(x, y, w, h, style.line_highlight) - color = style.accent - end - - -- icons - x = x + item.depth * style.padding.x + style.padding.x - if item.type == "dir" then - local icon1 = item.expanded and "-" or "+" - local icon2 = item.expanded and "D" or "d" - common.draw_text(style.icon_font, color, icon1, nil, x, y, 0, h) - x = x + style.padding.x - common.draw_text(style.icon_font, color, icon2, nil, x, y, 0, h) - x = x + icon_width - else - x = x + style.padding.x - common.draw_text(style.icon_font, color, "f", nil, x, y, 0, h) - x = x + icon_width - end - - -- text - x = x + spacing - x = common.draw_text(style.font, color, item.name, nil, x, y, 0, h) - end -end - - --- init -local view = TreeView() -local node = core.root_view:get_active_node() -node:split("left", view, true) - --- register commands and keymap -command.add(nil, { - ["treeview:toggle"] = function() - view.visible = not view.visible - end, -}) - -keymap.add { ["ctrl+\\"] = "treeview:toggle" } diff --git a/tools/lite/data/plugins/trimwhitespace.lua b/tools/lite/data/plugins/trimwhitespace.lua deleted file mode 100644 index d4d25c8..0000000 --- a/tools/lite/data/plugins/trimwhitespace.lua +++ /dev/null @@ -1,36 +0,0 @@ -local core = require "core" -local command = require "core.command" -local Doc = require "core.doc" - - -local function trim_trailing_whitespace(doc) - local cline, ccol = doc:get_selection() - for i = 1, #doc.lines do - local old_text = doc:get_text(i, 1, i, math.huge) - 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 - doc:insert(i, 1, new_text) - doc:remove(i, #new_text + 1, i, math.huge) - end - end -end - - -command.add("core.docview", { - ["trim-whitespace:trim-trailing-whitespace"] = function() - trim_trailing_whitespace(core.active_view.doc) - end, -}) - - -local save = Doc.save -Doc.save = function(self, ...) - trim_trailing_whitespace(self) - save(self, ...) -end diff --git a/tools/lite/data/user/colors/fall.lua b/tools/lite/data/user/colors/fall.lua deleted file mode 100644 index 0cab762..0000000 --- a/tools/lite/data/user/colors/fall.lua +++ /dev/null @@ -1,28 +0,0 @@ -local style = require "core.style" -local common = require "core.common" - -style.background = { common.color "#343233" } -style.background2 = { common.color "#2c2a2b" } -style.background3 = { common.color "#2c2a2b" } -style.text = { common.color "#c4b398" } -style.caret = { common.color "#61efce" } -style.accent = { common.color "#ffd152" } -style.dim = { common.color "#615d5f" } -style.divider = { common.color "#242223" } -style.selection = { common.color "#454244" } -style.line_number = { common.color "#454244" } -style.line_number2 = { common.color "#615d5f" } -style.line_highlight = { common.color "#383637" } -style.scrollbar = { common.color "#454344" } -style.scrollbar2 = { common.color "#524F50" } - -style.syntax["normal"] = { common.color "#efdab9" } -style.syntax["symbol"] = { common.color "#efdab9" } -style.syntax["comment"] = { common.color "#615d5f" } -style.syntax["keyword"] = { common.color "#d36e2d" } -style.syntax["keyword2"] = { common.color "#ef6179" } -style.syntax["number"] = { common.color "#ffd152" } -style.syntax["literal"] = { common.color "#ffd152" } -style.syntax["string"] = { common.color "#ffd152" } -style.syntax["operator"] = { common.color "#efdab9" } -style.syntax["function"] = { common.color "#61efce" } diff --git a/tools/lite/data/user/colors/summer.lua b/tools/lite/data/user/colors/summer.lua deleted file mode 100644 index 5e48cf7..0000000 --- a/tools/lite/data/user/colors/summer.lua +++ /dev/null @@ -1,28 +0,0 @@ -local style = require "core.style" -local common = require "core.common" - -style.background = { common.color "#fbfbfb" } -style.background2 = { common.color "#f2f2f2" } -style.background3 = { common.color "#f2f2f2" } -style.text = { common.color "#404040" } -style.caret = { common.color "#fc1785" } -style.accent = { common.color "#fc1785" } -style.dim = { common.color "#b0b0b0" } -style.divider = { common.color "#e8e8e8" } -style.selection = { common.color "#b7dce8" } -style.line_number = { common.color "#d0d0d0" } -style.line_number2 = { common.color "#808080" } -style.line_highlight = { common.color "#f2f2f2" } -style.scrollbar = { common.color "#e0e0e0" } -style.scrollbar2 = { common.color "#c0c0c0" } - -style.syntax["normal"] = { common.color "#181818" } -style.syntax["symbol"] = { common.color "#181818" } -style.syntax["comment"] = { common.color "#22a21f" } -style.syntax["keyword"] = { common.color "#fb6620" } -style.syntax["keyword2"] = { common.color "#fc1785" } -style.syntax["number"] = { common.color "#1586d2" } -style.syntax["literal"] = { common.color "#1586d2" } -style.syntax["string"] = { common.color "#1586d2" } -style.syntax["operator"] = { common.color "#fb6620" } -style.syntax["function"] = { common.color "#fc1785" } diff --git a/tools/lite/data/user/init.lua b/tools/lite/data/user/init.lua deleted file mode 100644 index c3ee210..0000000 --- a/tools/lite/data/user/init.lua +++ /dev/null @@ -1,31 +0,0 @@ --- put user settings here --- this module will be loaded after everything else when the application starts - -local keymap = require "core.keymap" -local config = require "core.config" -local style = require "core.style" - --- light theme: --- require "user.colors.summer" - --- key binding: --- keymap.add { ["ctrl+escape"] = "core:quit" } - - -local core = require "core" -local command = require "core.command" -local keymap = require "core.keymap" -local console = require "plugins.console" - -command.add(nil, { - ["project:build-project"] = function() - core.log "Building..." - console.run { - command = "chcp 65001 & make", - file_pattern = "(.*):(%d+):(%d+): (.*)$", - on_complete = function() core.log "Build complete" end, - } - end -}) - -keymap.add { ["ctrl+b"] = "project:build-project" } \ No newline at end of file diff --git a/tools/lite/lite b/tools/lite/lite deleted file mode 100644 index 3266cbd..0000000 Binary files a/tools/lite/lite and /dev/null differ diff --git a/tools/lite/lite.exe b/tools/lite/lite.exe deleted file mode 100644 index f464a02..0000000 Binary files a/tools/lite/lite.exe and /dev/null differ