Compare commits
314 Commits
Author | SHA1 | Date |
---|---|---|
George Sokianos | 2c0f92766f | |
George Sokianos | 3f6207b4af | |
George Sokianos | 79f42686a7 | |
George Sokianos | 9944a91f55 | |
George Sokianos | 19e95ed791 | |
George Sokianos | 759bccce52 | |
George Sokianos | a7971556d4 | |
George Sokianos | 6807a8e29a | |
George Sokianos | 1be1c7fb0b | |
George Sokianos | 7efe75fe7d | |
George Sokianos | 9c2eec9066 | |
George Sokianos | df8eaa64d1 | |
George Sokianos | ad4c221dd8 | |
George Sokianos | 66fb996e76 | |
takase1121 | c6a7ff98b0 | |
takase1121 | caf30574ed | |
takase1121 | 328ed55f83 | |
takase1121 | b4d750013d | |
Takase | b856dc371a | |
Takase | bbc524ad82 | |
vqn | a389adbaf5 | |
vqn | df12a5dde6 | |
Fiji | e353c5322a | |
Chloé Vulquin | 4ae92ae128 | |
vqn | 2ce8c58bea | |
George Sokianos | d0b86296c3 | |
George Sokianos | 71558986d3 | |
Velosofy | d67a951d31 | |
takase1121 | b68efcd9e4 | |
takase1121 | 97a49661e0 | |
vqn | 9c21903af7 | |
Adam Harrison | 1d4e01a192 | |
ThaCuber | f1bdd840a1 | |
George Sokianos | ffc5e25a72 | |
George Sokianos | 5c983f10b5 | |
George Sokianos | e4a2adf79b | |
George Sokianos | adc2919dfa | |
George Sokianos | 0f7e075d6f | |
George Sokianos | 1b00045146 | |
Guldoman | 34cebe8fe4 | |
Takase | 311651333a | |
Guldoman | 8e2928aeb8 | |
Guldoman | bc935906d1 | |
Guldoman | 9be5a46a22 | |
Guldoman | 885e6b3c50 | |
Guldoman | b1a647814f | |
Guldoman | 8eacca7ae1 | |
Guldoman | 19cef97bcd | |
Guldoman | c31a8ae0f6 | |
takase1121 | 9272f5ef2d | |
takase1121 | 88dcb25396 | |
takase1121 | 513432a784 | |
takase1121 | 43643a16c0 | |
Guldoman | 5c5c77219b | |
Guldoman | 6cd1f96234 | |
Adam | 3bf3266ca5 | |
Guldoman | 4adfd44d9f | |
Daniel Margarido | 35ef0a9484 | |
Guldoman | 01cab0611c | |
Guldoman | fb7ed49a44 | |
Takase | 34d163aa25 | |
Takase | 63d99d4431 | |
Takase | 5d53b13cf4 | |
Guldoman | 4005a46144 | |
Guldoman | 8c451928bf | |
Guldoman | a066190ee2 | |
Guldoman | 1ad3b70e9e | |
Takase | 82589526c0 | |
Guldoman | 316fbbe743 | |
Guldoman | 784b911d41 | |
Robert Hildebrandt | a9934c08d9 | |
Guldoman | 397b61e7c6 | |
Takase | 890e4882f3 | |
Takase | 09dd111c61 | |
Jan | d937693ddb | |
Guldoman | 3d93e16597 | |
Takase | eb27e543b4 | |
Guldoman | 86cfbe5f3b | |
Adam Harrison | c279ef0034 | |
Shreyas A S | 9120fb0046 | |
Delta-official | e62a672d7e | |
Takase | 07818934b6 | |
Takase | 5d0bcc99fa | |
Takase | b5b6682303 | |
Takase | ad0d280ecc | |
Takase | 553251834b | |
Takase | 7f84ed311b | |
Guldoman | f7400c924e | |
Guldoman | e9678cc140 | |
Luke aka SwissalpS | b5617a3eef | |
Luke aka SwissalpS | bd53bc3718 | |
Jan | 2af3082640 | |
Guldoman | 964b8fe29d | |
Guldoman | f1f81c8851 | |
Guldoman | 68e9c4670e | |
Guldoman | ff884d7d4a | |
Guldoman | 3febcf454c | |
Jefferson González | 6c17f6e2ee | |
takase1121 | 2a9b367e13 | |
takase1121 | 64e5fd8ead | |
takase1121 | 4c320a10c0 | |
Guldoman | bd36b3f615 | |
takase1121 | c0b1fe348f | |
takase1121 | 6111b071ec | |
Adam Harrison | 793af14dca | |
takase1121 | 2517d34113 | |
Takase | 1952848caa | |
Jan | 760271d416 | |
Takase | 2fe1f52a1f | |
Takase | 64a6d88618 | |
Guldoman | 97f3159415 | |
Takase | 8e57b71118 | |
Takase | a44a7eafe8 | |
Takase | 1fe90da664 | |
Jefferson González | 0d0f1b00d9 | |
vqn | f60228f610 | |
Guldoman | d497402c30 | |
Takase | fdd6ca3426 | |
Takase | 84aeea61c2 | |
Takase | a0c8f01312 | |
Takase | 4e3d6824ff | |
Takase | bb31a1adf2 | |
Takase | a24432941c | |
vqn | 12e0634f9c | |
Guldoman | 6d217204f6 | |
Adam | 6deca53303 | |
Guldoman | bf35417f82 | |
Takase | 84c7bb9de6 | |
Guldoman | 89864ee88c | |
Guldoman | a61531dbf0 | |
Guldoman | 1d0725f904 | |
Takase | 32860c111e | |
Guldoman | 8c47fad637 | |
Takase | f685293417 | |
Guldoman | 95611366bb | |
vqn | 067271bc02 | |
Adam | c8f033ec8b | |
Guldoman | b0e524dd15 | |
Jefferson González | 24491bc3fd | |
Jefferson González | 70ed171612 | |
Jefferson González | 6925c06599 | |
Takase | b95fdfcf5f | |
takase1121 | 218ba3ebac | |
Adam | 017711b369 | |
jgmdev | b8eb6865a6 | |
Jefferson González | 03d11c869d | |
Jan | a951c3cd39 | |
Adam Harrison | 5907118683 | |
Jefferson González | 95f18a1148 | |
Guldoman | bddb5e274d | |
Jan | d54a5d0672 | |
Adam Harrison | 4c18cf6744 | |
Guldoman | a9d8f12cb7 | |
xwii | 38fa9f976c | |
adityaraj | ae218bc005 | |
Jan | c8afe3d1bf | |
Takase | 2d0ddc302f | |
jgmdev | 291e7eab6f | |
sammyette | 1984573214 | |
Jan | f5a224999a | |
Jefferson González | 4b6134a839 | |
jgmdev | 60f0e3f3da | |
Guldoman | f00f41b468 | |
Julien Voisin | 1ab320bb9b | |
Guldoman | 138cea45d5 | |
Julien Voisin | d86413cc30 | |
Julien Voisin | d06c9f401c | |
Julien Voisin | d755fa6fba | |
Takase | 69ce580970 | |
Guldoman | bd4e64cc7e | |
Dave | 0fa0a59c8b | |
Takase | e0b5f56faa | |
Guldoman | 95c1805293 | |
Adam Harrison | e85a439656 | |
Shreyas A S | 09131e7ff6 | |
Guldoman | 4454fcc3a2 | |
Delta-official | a80414fb0b | |
Takase | 4e5c0ed1d4 | |
Adam | 5b62eba35f | |
Takase | d1d4436691 | |
Takase | 3ab1d7f198 | |
Takase | 691df348f0 | |
Adam | fbdd8fa318 | |
Takase | 60e71160b6 | |
Guldoman | 523e62bdce | |
Takase | fa694ae6f8 | |
Guldoman | 608ad159cd | |
Guldoman | 819bd81293 | |
Luke aka SwissalpS | d9aef2390c | |
Luke aka SwissalpS | 526fc816c4 | |
Jan | 0532ef1792 | |
Guldoman | 9328e7ae8f | |
Jan | dd479f8cd1 | |
Guldoman | 5758693f4f | |
Guldoman | 9b61f1c597 | |
Guldoman | d12a14869c | |
Guldoman | a01eba3fad | |
Guldoman | 48bcf66cc1 | |
Guldoman | ffb8f5da0f | |
Guldoman | 43f9b8accc | |
Jefferson González | 39182d49d6 | |
Jefferson González | 20fdcd668d | |
takase1121 | 554a4d4f48 | |
takase1121 | af2abe4c98 | |
Jefferson González | 3deeb762b4 | |
Adam | 3627bc01cf | |
Guldoman | f06580deee | |
takase1121 | 0766d804ba | |
takase1121 | 1d37fa1be3 | |
Adam Harrison | 116c14679d | |
Adam | 4f26fd1cf7 | |
takase1121 | c77b69a21c | |
Takase | c0c2e7222e | |
Jan | bd93e5a4b6 | |
jgmdev | 76a7fb9f79 | |
Takase | e667b16099 | |
Takase | 60fae68a2e | |
Guldoman | eb5c42a6c9 | |
Takase | 0dca16c462 | |
Guldoman | 10bd794d8a | |
Takase | 3e36443c9d | |
Takase | 3afcf84a09 | |
Jefferson González | d16dce4fb6 | |
sammyette | 945914b276 | |
vqn | 577e99f519 | |
Guldoman | 637064d351 | |
Takase | 688bcaf707 | |
Takase | f11cc18921 | |
Takase | 112fe7bddd | |
Takase | b623ad9b35 | |
Jan | 9fb714236b | |
Takase | d4ff3cb094 | |
Takase | 612ebebb1f | |
Adam | 9634715618 | |
vqn | 7f9030bfb4 | |
vqn | 6de18442be | |
Adam | acbd8715f4 | |
Guldoman | ca6fedd3f7 | |
Adam | b30ea9e9ef | |
Guldoman | c1adfb55d2 | |
Adam Harrison | c8977ca62b | |
Adam | b348acaa81 | |
Guldoman | d0ec3aa0fe | |
Takase | ef70faa2fd | |
Guldoman | 71e4adbd6f | |
Guldoman | e66174f9d8 | |
Guldoman | 94e2df991c | |
Guldoman | ca29728e34 | |
Takase | d31f128ef9 | |
Guldoman | 703b14170b | |
Takase | d27bd6b14d | |
Guldoman | 4784a32eed | |
Adam | 9284e92291 | |
vqn | 9b45c9bdbd | |
Adam | 1f0cdc6831 | |
Guldoman | cd8ec70d78 | |
jgmdev | 1fe0796a30 | |
Eric Gaudet | 5502f9e0a8 | |
Guldoman | 5f24108772 | |
Guldoman | a0c05791b1 | |
Jefferson González | 0e3b5935e6 | |
Jefferson González | 68108aeff2 | |
Jefferson González | 7f91514d6a | |
Jefferson González | 1fcc69d7aa | |
Guldoman | c40e19d9fe | |
Takase | 0423611a99 | |
vqn | 6fc9aebae0 | |
Himura Kazuto | 623419adfa | |
sammyette | 06cb09cb93 | |
Adam | 389449853a | |
Adam | 1378c3d6a7 | |
jgmdev | 8fb7a2d140 | |
Jefferson González | 763d727874 | |
Jan | 66815b24b0 | |
Adam Harrison | 30c9c52426 | |
Jefferson González | b1e52bb9d4 | |
Adam | 9b0a348a91 | |
Guldoman | 920d3ef1e3 | |
Jan | d062c9e593 | |
Adam Harrison | b676314b1a | |
Guldoman | 757b906ca2 | |
xwii | 90a7882ed4 | |
Merlin Volkmer | e52502b388 | |
adityaraj | 9a831cb206 | |
Jan | 4d35dc4969 | |
Takase | 8bd6244add | |
George Sokianos | 9134c115fe | |
George Sokianos | e4f3f1b744 | |
George Sokianos | 62adafb59d | |
George Sokianos | 65d95c7f40 | |
George Sokianos | 0cb20ab7b2 | |
George Sokianos | 789004ea2c | |
George Sokianos | 2bdfd5a694 | |
George Sokianos | a5f073d23b | |
George Sokianos | da2ba3aac2 | |
George Sokianos | f053ecde04 | |
George Sokianos | 98711e1cb5 | |
George Sokianos | b15bcbd397 | |
George Sokianos | 5d39b4ae68 | |
George Sokianos | 283f1d0837 | |
George Sokianos | 7b51ee99de | |
George Sokianos | 32eeb07c54 | |
George Sokianos | 69bd81188b | |
George Sokianos | ff3e5282f6 | |
George Sokianos | 89e2defb5b | |
George Sokianos | 1e90105944 | |
George Sokianos | f2e42ca2fa | |
George Sokianos | decd5deeae | |
George Sokianos | b5831ace20 | |
George Sokianos | 8fe3c75339 | |
George Sokianos | 9b599aaa78 | |
George Sokianos | ddb81648c2 | |
George Sokianos | b919e5b942 | |
George Sokianos | 05cf40c1c9 |
|
@ -9,13 +9,15 @@ on:
|
|||
inputs:
|
||||
version:
|
||||
description: Release Version
|
||||
default: v2.1.1
|
||||
default: v2.1.4
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
outputs:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
version: ${{ steps.tag.outputs.version }}
|
||||
|
|
|
@ -19,6 +19,12 @@ compile_commands.json
|
|||
error.txt
|
||||
lite-xl*
|
||||
LiteXL*
|
||||
lite
|
||||
.config/
|
||||
*.lha
|
||||
*.o
|
||||
*.snalyzerinfo
|
||||
|
||||
|
||||
!resources/windows/*.diff
|
||||
!resources/windows/*.exe.manifest.in
|
||||
|
|
4
LICENSE
4
LICENSE
|
@ -1,4 +1,6 @@
|
|||
Copyright (c) 2020-present Lite XL Team
|
||||
Copyright (c) 2020 rxi
|
||||
Copyright (c) 2020-2022 Francesco Abbate
|
||||
Copyright (c) 2022-present Lite XL Team
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
#
|
||||
# Project: Lite XL
|
||||
#
|
||||
# Created on: 26-12-2021
|
||||
#
|
||||
|
||||
LiteXL_OBJ := \
|
||||
src/main.o src/rencache.o src/renderer.o src/renwindow.o \
|
||||
src/api/api.o src/api/dirmonitor.o \
|
||||
src/api/regex.o src/api/renderer.o src/api/system.o \
|
||||
src/api/utf8.o src/platform/morphos.o \
|
||||
src/api/dirmonitor/mos.o src/platform/codesets.o
|
||||
|
||||
outfile := lite-xl
|
||||
compiler := ppc-morphos-gcc-11
|
||||
cxxcompiler := ppc-morphos-g++-11
|
||||
|
||||
INCPATH := -Isrc -Ilib/dmon -I/sdk/gg/usr/local/include/SDL2 \
|
||||
-I/sdk/gg/usr/include/freetype -I/sdk/gg/usr/include/lua5.4
|
||||
DFLAGS ?= -D__USE_INLINE__
|
||||
CFLAGS ?= -Wall -Wwrite-strings -O2 -noixemul -g -std=gnu11 -fno-strict-aliasing
|
||||
LFLAGS ?= -noixemul -lpcre2-8 -lSDL2 -llua54 -lagg -lfreetype -lm -lc -L/usr/local/lib
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
CFLAGS += -g -gstabs
|
||||
LFLAGS += -gstabs
|
||||
endif
|
||||
|
||||
.PHONY: LiteXL clean release
|
||||
|
||||
default: LiteXL
|
||||
|
||||
clean:
|
||||
@echo "Cleaning compiler objects..."
|
||||
@rm -f $(LiteXL_OBJ)
|
||||
|
||||
LiteXL: $(LiteXL_OBJ)
|
||||
@echo "Linking LiteXL"
|
||||
$(compiler) -o $(outfile) $(LiteXL_OBJ) $(LFLAGS)
|
||||
|
||||
.c.o:
|
||||
@echo "Compiling $<"
|
||||
$(compiler) -c $< -o $*.o $(CFLAGS) $(INCPATH) $(DFLAGS)
|
||||
|
||||
src/main.o: src/main.c src/api/api.h src/rencache.h \
|
||||
src/renderer.h src/platform/morphos.h
|
||||
|
||||
src/rencache.o: src/rencache.c
|
||||
|
||||
src/renderer.o: src/renderer.c
|
||||
|
||||
src/renwindow.o: src/renwindow.c
|
||||
|
||||
src/api/api.o: src/api/api.c
|
||||
|
||||
src/api/regex.o: src/api/regex.c
|
||||
|
||||
src/api/renderer.o: src/api/renderer.c
|
||||
|
||||
src/api/system.o: src/api/system.c
|
||||
|
||||
src/platform/morphos.o: src/platform/morphos.c
|
||||
|
||||
src/api/dirmonitor.o: src/api/dirmonitor.c src/api/dirmonitor/mos.c
|
||||
|
||||
src/api/utf8.o: src/api/utf8.c
|
||||
|
||||
src/api/dirmonitor/mos.o: src/api/dirmonitor/mos.c
|
||||
|
||||
src/platform/codesets.o: src/platform/codesets.c
|
||||
|
||||
release: clean LiteXL
|
||||
@echo "Creating release files..."
|
||||
@mkdir -p release/LiteXL2
|
||||
@cp -r resources/amiga/* release/LiteXL2/
|
||||
@mv release/LiteXL2/LiteXL2.info release/
|
||||
@rm release/LiteXL2/AutoInstall
|
||||
@cp -r data release/LiteXL2/
|
||||
@cp changelog.md release/LiteXL2/
|
||||
@cp $(outfile) release/LiteXL2/
|
||||
@strip release/LiteXL2/$(outfile)
|
||||
@cp README.md release/LiteXL2/
|
||||
@cp README_Amiga.md release/LiteXL2/
|
||||
@cp LICENSE release/LiteXL2/
|
||||
@cp -r licenses release/LiteXL2/
|
||||
@echo "Creating release archive..."
|
||||
@lha -aeqr3 a LiteXL2_MOS.lha release/
|
||||
@echo "Clean release files..."
|
||||
@delete release ALL QUIET FORCE
|
|
@ -0,0 +1,102 @@
|
|||
#
|
||||
# Project: Lite XL
|
||||
#
|
||||
# Created on: 26-12-2021
|
||||
#
|
||||
|
||||
LiteXL_OBJ := \
|
||||
src/main.o src/rencache.o src/renderer.o src/renwindow.o \
|
||||
src/api/api.o src/api/dirmonitor.o \
|
||||
src/api/regex.o src/api/renderer.o src/api/system.o \
|
||||
src/api/utf8.o src/platform/amigaos4.o \
|
||||
src/api/dirmonitor/os4.o src/platform/codesets.o
|
||||
|
||||
outfile := lite-xl
|
||||
compiler := gcc
|
||||
cxxcompiler := g++
|
||||
|
||||
INCPATH := -Isrc -I/sdk/local/newlib/include/SDL2 \
|
||||
-I/sdk/local/common/include/lua54 -I/sdk/local/common/include/freetype2
|
||||
|
||||
DFLAGS += -D__USE_INLINE__ -DLITE_XL_DATA_USE_EXEDIR
|
||||
CFLAGS ?= -Werror -Wwrite-strings -O3 -std=gnu11 -fno-strict-aliasing
|
||||
LFLAGS ?= -mcrt=newlib -lpcre2-8 -lSDL2 -llua54 -lfreetype -lpng -lz \
|
||||
-lpthread -athread=native
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
CFLAGS += -g -gstabs
|
||||
LFLAGS += -gstabs
|
||||
|
||||
ifeq ($(PROFYLER),1)
|
||||
CFLAGS += -finstrument-functions -fno-inline -DPROFILING
|
||||
LFLAGS += -lprofyle
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
|
||||
.PHONY: LiteXL clean release
|
||||
|
||||
default: LiteXL
|
||||
|
||||
clean:
|
||||
@echo "Cleaning compiler objects..."
|
||||
@rm -f $(LiteXL_OBJ)
|
||||
|
||||
LiteXL: $(LiteXL_OBJ)
|
||||
@echo "Linking LiteXL"
|
||||
@$(compiler) -o $(outfile) $(LiteXL_OBJ) $(LFLAGS)
|
||||
|
||||
|
||||
.c.o:
|
||||
@echo "Compiling $<"
|
||||
@$(compiler) -c $< -o $*.o $(CFLAGS) $(INCPATH) $(DFLAGS)
|
||||
|
||||
|
||||
src/main.o: src/main.c src/api/api.h src/rencache.h \
|
||||
src/renderer.h src/platform/amigaos4.h src/platform/codesets.h
|
||||
|
||||
src/rencache.o: src/rencache.c
|
||||
|
||||
src/renderer.o: src/renderer.c
|
||||
|
||||
src/renwindow.o: src/renwindow.c
|
||||
|
||||
src/api/api.o: src/api/api.c
|
||||
|
||||
src/api/regex.o: src/api/regex.c
|
||||
|
||||
src/api/renderer.o: src/api/renderer.c
|
||||
|
||||
src/api/system.o: src/api/system.c src/platform/amigaos4.h
|
||||
|
||||
src/platform/amigaos4.o: src/platform/amigaos4.c
|
||||
|
||||
src/platform/codesets.o: src/platform/codesets.c
|
||||
|
||||
src/api/dirmonitor.o: src/api/dirmonitor.c src/api/dirmonitor/os4.c
|
||||
|
||||
src/api/utf8.o: src/api/utf8.c src/platform/amigaos4.h
|
||||
|
||||
src/api/dirmonitor/os4.o: src/api/dirmonitor/os4.c
|
||||
|
||||
src/api/process.o: src/api/process.c
|
||||
|
||||
release: clean LiteXL
|
||||
@echo "Creating release files..."
|
||||
@mkdir -p release/LiteXL2
|
||||
@cp -r resources/amiga/* release/LiteXL2/
|
||||
@mv release/LiteXL2/LiteXL2.info release/
|
||||
@mv release/LiteXL2/AutoInstall release/
|
||||
@cp -r data release/LiteXL2/
|
||||
@cp changelog.md release/LiteXL2/
|
||||
@cp $(outfile) release/LiteXL2/
|
||||
@strip release/LiteXL2/$(outfile)
|
||||
@cp README.md release/LiteXL2/
|
||||
@cp README_Amiga.md release/LiteXL2/
|
||||
@cp LICENSE release/LiteXL2/
|
||||
@cp -r licenses release/LiteXL2/
|
||||
@echo "Creating release archive..."
|
||||
@lha -aeqr3 a LiteXL2_OS4.lha release/
|
||||
@echo "Clean release files..."
|
||||
@delete release ALL QUIET FORCE
|
52
README.md
52
README.md
|
@ -1,7 +1,7 @@
|
|||
# Lite XL
|
||||
|
||||
[![CI]](https://github.com/lite-xl/lite-xl/actions/workflows/build.yml)
|
||||
[![Discord Badge Image]](https://discord.gg/UQKnzBhY5H)
|
||||
[![Discord Badge Image]](https://discord.gg/RWzqC3nx7K)
|
||||
|
||||
![screenshot-dark]
|
||||
|
||||
|
@ -124,7 +124,6 @@ cd lite-xl
|
|||
```
|
||||
|
||||
To run lite-xl without installing:
|
||||
|
||||
```sh
|
||||
./lite-xl
|
||||
```
|
||||
|
@ -137,68 +136,31 @@ mkdir -p $HOME/.local/bin && cp lite-xl $HOME/.local/bin/
|
|||
mkdir -p $HOME/.local/share/lite-xl && cp -r data/* $HOME/.local/share/lite-xl/
|
||||
```
|
||||
|
||||
#### Add Lite XL to PATH
|
||||
|
||||
To run Lite XL from the command line, you must add it to PATH.
|
||||
|
||||
If `$HOME/.local/bin` is not in PATH:
|
||||
|
||||
```sh
|
||||
echo -e 'export PATH=$PATH:$HOME/.local/bin' >> $HOME/.bashrc
|
||||
```
|
||||
|
||||
Alternatively on recent versions of GNOME and KDE Plasma,
|
||||
you can add `$HOME/.local/bin` to PATH via `~/.config/environment.d/envvars.conf`:
|
||||
|
||||
```ini
|
||||
PATH=$HOME/.local/bin:$PATH
|
||||
```
|
||||
|
||||
> **Note**
|
||||
> Some systems might not load `.bashrc` when logging in.
|
||||
> This can cause problems with launching applications from the desktop / menu.
|
||||
|
||||
#### Add Lite XL to application launchers
|
||||
|
||||
To get the icon to show up in app launcher, you need to create a desktop
|
||||
entry and put it into `/usr/share/applications` or `~/.local/share/applications`.
|
||||
|
||||
Here is an example for a desktop entry in `~/.local/share/applications/com.lite_xl.LiteXL.desktop`,
|
||||
assuming Lite XL is in PATH:
|
||||
|
||||
```ini
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Lite XL
|
||||
Comment=A lightweight text editor written in Lua
|
||||
Exec=lite-xl %F
|
||||
Icon=lite-xl
|
||||
Terminal=false
|
||||
StartupWMClass=lite-xl
|
||||
Categories=Development;IDE;
|
||||
MimeType=text/plain;inode/directory;
|
||||
```
|
||||
|
||||
To get the icon to show up in app launcher immediately, run:
|
||||
To get the icon to show up in app launcher:
|
||||
|
||||
```sh
|
||||
xdg-desktop-menu forceupdate
|
||||
```
|
||||
|
||||
Alternatively, you may log out and log in again.
|
||||
You may need to logout and login again to see icon in app launcher.
|
||||
|
||||
#### Uninstall
|
||||
|
||||
To uninstall Lite XL, run:
|
||||
To uninstall just run:
|
||||
|
||||
```sh
|
||||
rm -f $HOME/.local/bin/lite-xl
|
||||
rm -rf $HOME/.local/share/icons/hicolor/scalable/apps/lite-xl.svg \
|
||||
$HOME/.local/share/applications/com.lite_xl.LiteXL.desktop \
|
||||
$HOME/.local/share/metainfo/com.lite_xl.LiteXL.appdata.xml \
|
||||
$HOME/.local/share/applications/org.lite_xl.lite_xl.desktop \
|
||||
$HOME/.local/share/metainfo/org.lite_xl.lite_xl.appdata.xml \
|
||||
$HOME/.local/share/lite-xl
|
||||
```
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
Any additional functionality that can be added through a plugin should be done
|
||||
|
|
|
@ -0,0 +1,368 @@
|
|||
# Lite XL v2 for AmigaOS 4.1 FE & MorphOS 3
|
||||
|
||||
Lite XL is a lightweight text editor written in Lua and SDL2.
|
||||
|
||||
The port is not perfect and it might have issues here and there. It might
|
||||
crash from time to time, if there is a path problem, but overall it works
|
||||
pretty well. This is my daily editor for any kind of development.
|
||||
If it crashes on your system, try to delete to `.config` folder.
|
||||
|
||||
## Installation
|
||||
You can extract the Lite XL archive wherever you want and run the *lite*
|
||||
editor.
|
||||
|
||||
## Configuration folder
|
||||
This editor creates a `.config` folder where the configuration is saved, as
|
||||
well as plugins, themes etc.. By default this version uses the installation
|
||||
folder, but if you want to override it, you can create an ENV variable
|
||||
named `HOME` and set there your prefferable path.
|
||||
|
||||
You can check if there is one already set by executing the following command
|
||||
in a shell
|
||||
```
|
||||
GetEnv HOME
|
||||
```
|
||||
If there is one set, then you will see the path at the output.
|
||||
|
||||
Otherwise, you can set your home path be executing the following command.
|
||||
Change the path to the one of your preference.
|
||||
```
|
||||
SetEnv SAVE HOME "Sys:home/"
|
||||
```
|
||||
|
||||
## Addons
|
||||
### Colors
|
||||
Colors are lua files that set the color scheme of the editor. There are
|
||||
light and dark themes for you to choose.
|
||||
|
||||
To install and use them you have to copy the ones you would like from
|
||||
`addons/colors/light` or `addons/colors/dark` into the folder
|
||||
`.config/lite-xl/colors/`. Don't add light or dark folders. Just copy the
|
||||
.lua files in there.
|
||||
|
||||
Then you have to start Lite XL and open your configuration by clicking
|
||||
at the cog icon at the toolbar (bottom left sixth icon). Go at the line
|
||||
that looks like below
|
||||
```
|
||||
-- core.reload_module("colors.summer")
|
||||
```
|
||||
and change the `summer` with the name of your color theme. Also, remove
|
||||
the two dashes `--` at the start of the line and save the file. If you
|
||||
did everything right, the color schema should change instantly.
|
||||
|
||||
The themes can also be found at
|
||||
https://github.com/lite-xl/lite-xl-colors
|
||||
|
||||
### Plugins
|
||||
LiteXL is able to use plugins to extend its features. Those can be found
|
||||
at https://github.com/lite-xl/lite-xl-plugins and other websites. Not all
|
||||
of them will work fine on AmigaOS 4 or MorphOS, because of missing
|
||||
dependencies or filesystem issues.
|
||||
|
||||
To make it easier for you, I gathered some of the plugins that are working
|
||||
well, and I included them under `addons/plugins`. For you to install the
|
||||
ones you would like to use, you have to copy the `.lua` files into the
|
||||
folder `.config/lite-xl/plugins/` and restart the editor.
|
||||
|
||||
Please, choose wisely, because adding all the plugins might make the editor
|
||||
slower on your system. I would recommend you add only those that you really
|
||||
need.
|
||||
|
||||
The included plugins are the following:
|
||||
|
||||
**autoinsert**
|
||||
Automatically inserts closing brackets and quotes. Also allows selected
|
||||
text to be wrapped with brackets or quotes.
|
||||
|
||||
**autosaveonfocuslost**
|
||||
Automatically saves files that were changed when the main window loses
|
||||
focus by switching to another application
|
||||
|
||||
**autowrap**
|
||||
Automatically hardwraps lines when typing
|
||||
|
||||
**bigclock**
|
||||
Shows the current time and date in a view with large text
|
||||
|
||||
**bracketmatch**
|
||||
Underlines matching pair for bracket under the caret
|
||||
|
||||
**codesets**
|
||||
This plugin uses the codesets.library on AmigaOS 4 and the
|
||||
charsets.library on MorphOS to translate ISO encoded files to unicode
|
||||
and vice-versa. When this is enabled new menu items are added to
|
||||
load/save the code with a different encoding. Also there is a new
|
||||
section at the status bar that show the file encoding.
|
||||
This plugin is **EXPERIMENTAL** and heavily inspired from the encoding
|
||||
plugin at https://github.com/jgmdev/lite-xl-encoding
|
||||
|
||||
**colorpreview**
|
||||
Underlays color values (eg. `#ff00ff` or `rgb(255, 0, 255)`) with their
|
||||
resultant color.
|
||||
|
||||
**custom_caret**
|
||||
Customize the caret in the editor setting it to *underline*, *block* or
|
||||
*line* at the init.lua file in your config folder.
|
||||
For example add:
|
||||
`config.plugins.custom_caret.shape = "block"`
|
||||
|
||||
**EditorConfig**
|
||||
EditorConfig (https://editorconfig.org/) implementation for Lite XL
|
||||
|
||||
**ephemeral_tabs**
|
||||
Preview tabs. Opening a doc will replace the contents of the preview tab.
|
||||
Marks tabs as non-preview on any change or tab double clicking.
|
||||
|
||||
**ghmarkdown**
|
||||
Opens a preview of the current markdown file in a browser window.
|
||||
On AmigaOS 4 it uses *urlopen* and on MorphOS it uses *openurl* to load
|
||||
the generated html in the browser. It requires a GitHub application token
|
||||
because it uses its Rest API. Add it at the init.lua file in your config
|
||||
folder like below:
|
||||
`config.plugins.ghmarkdown.github_token = "<token here>"`
|
||||
|
||||
**indentguide**
|
||||
Adds indent guides
|
||||
|
||||
**language_guide**
|
||||
Syntax for the AmigaGuide scripting language
|
||||
|
||||
**language_hws**
|
||||
Syntax for the Hollywood language
|
||||
|
||||
**language_make**
|
||||
Syntax for the Make build system language
|
||||
|
||||
**language_sh**
|
||||
Syntax for shell scripting language
|
||||
|
||||
**lfautoinsert**
|
||||
Automatically inserts indentation and closing bracket/text after newline
|
||||
|
||||
**markers**
|
||||
Add markers to docs and jump between them quickly
|
||||
|
||||
**minimap**
|
||||
Shows a minimap on the right-hand side of the docview. Please note that
|
||||
this plugin will make the editor slower on file loading and scrolling.
|
||||
|
||||
**navigate**
|
||||
Allows moving back and forward between document positions, reducing the
|
||||
amount of scrolling
|
||||
|
||||
**nonicons**
|
||||
File icons set for TreeView. Download TTF font to your config/fonts
|
||||
folder from https://github.com/yamatsum/nonicons/tree/master/dist
|
||||
|
||||
**opacity**
|
||||
Change the opaqueness/transparency of lite-xl using LAmiga+mousewheel
|
||||
or a command.
|
||||
|
||||
**openfilelocation**
|
||||
Opens the parent directory of the current file in the file manager
|
||||
|
||||
**rainbowparen**
|
||||
Show nesting of parentheses with rainbow colours
|
||||
|
||||
**restoretabs**
|
||||
Keep a list of recently closed tabs, and restore the tab in order on
|
||||
cntrl+shift+t.
|
||||
|
||||
**select_colorscheme**
|
||||
Select a color theme, like VScode, Sublime Text.
|
||||
(plugin saves changes)
|
||||
|
||||
**selectionhighlight**
|
||||
Highlights regions of code that match the current selection
|
||||
|
||||
**smallclock**
|
||||
It adds a small clock at the bottom right corner.
|
||||
|
||||
**tetris**
|
||||
Play Tetris inside Lite XL.
|
||||
|
||||
## Tips and tricks
|
||||
### Transitions
|
||||
|
||||
If you want to disable the transitions and make the editor faster,
|
||||
open your configuration file by clicking at the cog icon at the toolbar
|
||||
(bottom left, 6th icon) and add the following line at the end of the file,
|
||||
and then save it. You might need to restart your editor.
|
||||
|
||||
```
|
||||
config.transitions = false
|
||||
```
|
||||
|
||||
### Hide files from the file list
|
||||
|
||||
If you would like to hide files or whole folder from the left side bar list,
|
||||
open your configuration by clicking at the cog icon at the toolbar
|
||||
(bottom left sixth icon) and add the followline at the end of the file and
|
||||
save it. This hides all the files that start with a dot, and all the `.info`
|
||||
files. You might need to restart your editor.
|
||||
|
||||
```
|
||||
config.ignore_files = {"^%.", "%.info$"}
|
||||
```
|
||||
|
||||
You can add as many rules as you want in there, to hide files or
|
||||
folders, as you like.
|
||||
|
||||
## I would like to thank
|
||||
|
||||
- IconDesigner for the proper glow icons that are included in the release
|
||||
- Capehill for his tireless work on SDL port for AmigaOS 4.1 FE
|
||||
- Michael Trebilcock for his port on liblua
|
||||
- Bruno "BeWorld" Peloille for his great work on porting SDL to MorphOS
|
||||
and for his valuable help
|
||||
- Lite XL original team for being helpful and providing info
|
||||
|
||||
Without all the above Lite XL would not be possible
|
||||
|
||||
## Support
|
||||
If you enjoy what I am doing and would like to keep me up during the night,
|
||||
please consider to buy me a coffee at:
|
||||
https://ko-fi.com/walkero
|
||||
|
||||
## Known issues
|
||||
You can find the known issues at
|
||||
https://git.walkero.gr/walkero/lite-xl/issues
|
||||
|
||||
# Changelog
|
||||
|
||||
## [2.1.4r1] - future
|
||||
### Added
|
||||
- Added the ability to open files and folders by drag 'n drop them on the
|
||||
LiteXL icon when this is on the AmiDock
|
||||
|
||||
### Updated
|
||||
- Updated the code to the upstream 2.1.4 release
|
||||
|
||||
### Fixed
|
||||
- Fix opening files from the root of a device
|
||||
|
||||
## [2.1.3r1] - 2024-03-09
|
||||
### Added
|
||||
- Added AmiUpdate support
|
||||
- Added the Tetris plugin
|
||||
|
||||
### Updated
|
||||
- Updated the code to the upstream 2.1.3 release
|
||||
- Compiled with SDL 2.30.0 that supports editing with ISO encodings, other
|
||||
than English. Now the editor should be able to support any language
|
||||
and in conjuction with the codesets plugin be able to make text
|
||||
encodings conversions
|
||||
- Now the codesets plugin supports MorphOS 3.18 and above
|
||||
|
||||
### Changed
|
||||
- Changed the way the "Open in system" option executes the WBRun command
|
||||
in AmigaOS 4, with a more secure way
|
||||
- Did a lot of code cleanup in sync with the upstream, and parts of code
|
||||
that were left over
|
||||
- Compiled with pcre2 10.42 (MorphOS version only)
|
||||
|
||||
### Fixed
|
||||
- I did a lot of changes on path manipulation and usage, fixing scanning
|
||||
the root of a partition or an assign path
|
||||
- Fixed an error with the codesets plugin, where an empty file could
|
||||
not be opened
|
||||
- Improved the folder suggestions when opening projects or changing paths.
|
||||
Now even the root folders of a partition are presented
|
||||
- Fixed ghmarkdown plugin, but now requires a GitHub token to be provided
|
||||
|
||||
## [2.1.2r1] - 2023-12-19
|
||||
### Added
|
||||
- Added the new experimental codesets plugin (AmigaOS4 version only).
|
||||
MorphOS version is in WIP
|
||||
|
||||
### Changed
|
||||
- Synced with the latest upstream v2.1.2 code
|
||||
- Compiled with gcc 11.3.0
|
||||
- Compiled with SDL 2.28.4
|
||||
- Compiled with libfreetype 2.13.x
|
||||
- Compiled with lua 5.4.6
|
||||
- Compiled with linpng 1.6.40 (AmigaOS4 version only)
|
||||
- Compiled with libz 1.2.13 (AmigaOS4 version only)
|
||||
|
||||
## [2.1.1r2] - 2022-05-14
|
||||
### Changed
|
||||
- Compiled with latest SDL v2.26.5-rc2
|
||||
|
||||
## [2.1.1r1] - 2022-01-29
|
||||
### Changed
|
||||
- Binary name changed to lite-xl
|
||||
- Updated the colour themes and the plugins that are included in the release
|
||||
- Compiled with latest SDL 2.26
|
||||
- Compiled with gcc 11
|
||||
- Synced the code with the upstream master branch at 8th January 2023
|
||||
|
||||
### Fixed
|
||||
- Set the default locale on AmigaOS 4, so as to fix some issues with decimal
|
||||
numbers
|
||||
|
||||
## [2.1.0r1] - 2022-10-10
|
||||
### Added
|
||||
- This version of LiteXL recognises changes that are done outside the editor
|
||||
in files and folders, and updates the items when it gets focus again.
|
||||
|
||||
### Changed
|
||||
- Synced the code with the latest upstream master branch, which means that
|
||||
this version is based on the latest available source
|
||||
- Now the plugins need to be version 3. The older versions will not work.
|
||||
All the included plugins are updated to the latest available version.
|
||||
- Compiled with SDL 2.24
|
||||
- Compiled with Lua 5.4
|
||||
|
||||
### Fixed
|
||||
- Fixed regex issues with some plugins
|
||||
- Fixed "Open in System" on AmigaOS 4 and MorphOS. When you right click
|
||||
at a file or a folder at the treeview at the left side, then depending
|
||||
the type of the item opens on Workbench. A folder opens in a list view
|
||||
and a file opens with its default tool
|
||||
- Fixed markdown preview on MorphOS. Now, it calls openurl with the html
|
||||
file (#20)
|
||||
- Fixed locale issues on MorphOS (again), since the previous fix didn't
|
||||
actually fixed the problem
|
||||
|
||||
## [2.0.3r3] - 2022-09-26
|
||||
### Added
|
||||
- Added plugin for AmigaGuide files
|
||||
- Added plugin for Hollywood files
|
||||
|
||||
### Fixed
|
||||
- Fixed non existing path crashes on OS4 and MorphOS
|
||||
- Fixed editor refresh whenever init.lua is changed, no matter the working
|
||||
folder
|
||||
- Fixed an issue when the user added a directory in the project that
|
||||
already existed
|
||||
- Fixed locale issue on start for MorphOS. Now it should start just fine
|
||||
no matter what locale the user has on his system.
|
||||
- Fixed "Find" on MorphOS that was not working (shortcut CTRL+F)
|
||||
- If the user selects to change the project folder and inserts Sys: or any
|
||||
partition name, the included folders will be listed as suggestions
|
||||
|
||||
### Changed
|
||||
- Removed linking with unix on OS4 build
|
||||
- Makefiles updated
|
||||
|
||||
## [2.0.3r2] - 2022-06-18
|
||||
### Added
|
||||
- First public MorphOS version released
|
||||
|
||||
### Changed
|
||||
- Merged source code for both AmigaOS 4 and MorphOS
|
||||
- Moved the declaration of the $VER and $STACK for the AmigaOS 4 version,
|
||||
so to happen only once (reported by capehill)
|
||||
|
||||
### Fixed
|
||||
- Fixed the usage of NumPad (reported by root)
|
||||
|
||||
## [2.0.3r1] - 2022-03-30
|
||||
### Changed
|
||||
- Applied all the necessary changes to make it run under AmigaOS 4.1 FE
|
||||
- Fixes and changes
|
||||
|
||||
# Disclaimer
|
||||
YOU MAY USE IT AT YOUR OWN RISK!
|
||||
I will not be held responsible for any data loss or problems you might get
|
||||
by using this software.
|
Binary file not shown.
503
changelog.md
503
changelog.md
|
@ -1,5 +1,505 @@
|
|||
# Changes Log
|
||||
|
||||
## [2.1.4] - 2024-04-16
|
||||
|
||||
This release addresses severe bugs not found in previous releases,
|
||||
and improves the usability of the program.
|
||||
|
||||
### Features
|
||||
|
||||
* Add `.pyi` extension to `language_python`.
|
||||
([#1728](https://github.com/lite-xl/lite-xl/pull/1728))
|
||||
|
||||
* Improve autocomplete suggestions box behavior with long text
|
||||
([#1734](https://github.com/lite-xl/lite-xl/pull/1734))
|
||||
|
||||
* Improve `CommandView` and autocomplete scroll behavior
|
||||
([#1732](https://github.com/lite-xl/lite-xl/pull/1732))
|
||||
|
||||
* Add `from` symbol to support ESM
|
||||
([#1754](https://github.com/lite-xl/lite-xl/pull/1754))
|
||||
|
||||
* Add Arduino syntax highlighting support in `language_cpp`
|
||||
([#1767](https://github.com/lite-xl/lite-xl/pull/1767))
|
||||
|
||||
* Skip patterns matching nothing in tokenizer
|
||||
([#1743](https://github.com/lite-xl/lite-xl/pull/1743))
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fix uninitialized variables in `src/api/process.c`
|
||||
([#1719](https://github.com/lite-xl/lite-xl/pull/1719))
|
||||
|
||||
* Fix `language_js` regex/comment distinction
|
||||
([#1731](https://github.com/lite-xl/lite-xl/pull/1731))
|
||||
|
||||
* Fix compilation on non-MINGW64 platforms
|
||||
([#1739](https://github.com/lite-xl/lite-xl/pull/1739))
|
||||
|
||||
* Limit `language_js` regex avoidance to numbers, and fix starting `/*` comments
|
||||
([#1744](https://github.com/lite-xl/lite-xl/pull/1744))
|
||||
|
||||
* Fix `buffer_size` in `g_read` for Windows
|
||||
([#1722](https://github.com/lite-xl/lite-xl/pull/1722))
|
||||
|
||||
* Fix missing permission for creating releases
|
||||
([#1770](https://github.com/lite-xl/lite-xl/pull/1770))
|
||||
|
||||
### Other Changes
|
||||
|
||||
* Rectify LICENSE dates and owners
|
||||
([#1748](https://github.com/lite-xl/lite-xl/pull/1748))
|
||||
|
||||
* Fix some typos in `core.init`
|
||||
([#1755](https://github.com/lite-xl/lite-xl/pull/1755))
|
||||
|
||||
## [2.1.3] - 2024-01-29
|
||||
|
||||
This release addresses severe bugs not found in previous releases.
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fix `doc:create-cursor-{previous,next}-line` with tabs
|
||||
([#1697](https://github.com/lite-xl/lite-xl/pull/1697))
|
||||
|
||||
* Fix heap buffer overflow and memory leaks in process and renderer API
|
||||
([#1705](https://github.com/lite-xl/lite-xl/pull/1705))
|
||||
|
||||
* Improve Python number syntax highlighting
|
||||
([#1704](https://github.com/lite-xl/lite-xl/pull/1704))
|
||||
|
||||
* Fix inconsistent NagView options on `doc:save`
|
||||
([#1696](https://github.com/lite-xl/lite-xl/pull/1696))
|
||||
|
||||
* Fix crashes with autoreload when files are deleted externally and replaced with a directory.
|
||||
([#1698](https://github.com/lite-xl/lite-xl/pull/1698))
|
||||
|
||||
* Improve JavaScript number syntax highlighting
|
||||
([#1710](https://github.com/lite-xl/lite-xl/pull/1710))
|
||||
|
||||
### Other Changes
|
||||
|
||||
* Process API style changes
|
||||
([#1709](https://github.com/lite-xl/lite-xl/pull/1709))
|
||||
|
||||
## [2.1.2] - 2023-12-29
|
||||
|
||||
This release addresses some issues present in the previous release,
|
||||
and improves the performance and stability of Lite XL.
|
||||
|
||||
### New Features
|
||||
|
||||
* The context menu in TreeView is now navigable with a keyboard.
|
||||
([#1338](https://github.com/lite-xl/lite-xl/pull/1338))
|
||||
|
||||
* A universal build of Lite XL is now available for macOS.
|
||||
This build runs natively on both Intel and Apple Silicon macs.
|
||||
([#1458](https://github.com/lite-xl/lite-xl/pull/1458))
|
||||
|
||||
* Most Unicode characters should be displayed properly
|
||||
if your fonts support them.
|
||||
([#1524](https://github.com/lite-xl/lite-xl/pull/1524))
|
||||
|
||||
* LogView will no longer scroll automatically if the user had scrolled.
|
||||
The LogView will only scroll automatically when the user scrolls up
|
||||
to the last entry.
|
||||
([#1546](https://github.com/lite-xl/lite-xl/pull/1546))
|
||||
|
||||
* When using different fonts (especially fonts that render different scripts),
|
||||
the letters will be aligned vertically.
|
||||
([#1560](https://github.com/lite-xl/lite-xl/pull/1560))
|
||||
|
||||
* Unsaved named files are now saved in the workspace.
|
||||
([#1597](https://github.com/lite-xl/lite-xl/pull/1597))
|
||||
|
||||
* macOS builds are now signed with a developer certificate.
|
||||
This allows the user to right click the application in Finder and execute
|
||||
it directly.
|
||||
([#1656](https://github.com/lite-xl/lite-xl/pull/1656))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* Allow command buffer to be expanded.
|
||||
([#1297](https://github.com/lite-xl/lite-xl/pull/1297))
|
||||
|
||||
* Use table.move to implement `common.splice`.
|
||||
([#1324](https://github.com/lite-xl/lite-xl/pull/1324))
|
||||
|
||||
* Create renderer only when it doesn't exist.
|
||||
([#1315](https://github.com/lite-xl/lite-xl/pull/1315))
|
||||
|
||||
* Avoid drawing hidden text in `DocView:draw_line_text`.
|
||||
([#1298](https://github.com/lite-xl/lite-xl/pull/1298))
|
||||
|
||||
* Don't calculate widths per-uft8-char when not needed.
|
||||
([#1409](https://github.com/lite-xl/lite-xl/pull/1409))
|
||||
|
||||
* Allow tokenizer to pause and resume in the middle of a line.
|
||||
([#1444](https://github.com/lite-xl/lite-xl/pull/1444))
|
||||
|
||||
* Optimize CI build times on MSYS2.
|
||||
([#1435](https://github.com/lite-xl/lite-xl/pull/1435))
|
||||
|
||||
* Significant memory usage improvements when using huge fonts on Windows.
|
||||
([#1555](https://github.com/lite-xl/lite-xl/pull/1555))
|
||||
|
||||
* Optimize background tasks response time.
|
||||
([#1601](https://github.com/lite-xl/lite-xl/pull/1601))
|
||||
|
||||
### Backward Incompatible Changes
|
||||
|
||||
* The native plugin API is now usable on multiple source files,
|
||||
without causing any duplicated symbol errors during compilation.
|
||||
Plugins using the new plugin API header must define `LITE_XL_PLUGIN_ENTRYPOINT`
|
||||
before importing the header, in one of their source files.
|
||||
([#1335](https://github.com/lite-xl/lite-xl/pull/1335))
|
||||
|
||||
* The native plugin API header now follows the Lua 5.4 API.
|
||||
Previously, the plugin API header followed the Lua 5.2 API.
|
||||
([#1436](https://github.com/lite-xl/lite-xl/pull/1436))
|
||||
|
||||
* On Linux, `process.start()` will now throw an error if `execv()` fails.
|
||||
([#1363](https://github.com/lite-xl/lite-xl/pull/1363))
|
||||
|
||||
* Lite XL will use the default `SCALE` of 1 due to unreliable display
|
||||
scale detection. This may be fixed in a later version of Lite XL.
|
||||
Set the `LITE_SCALE` environment variable to override this value.
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fix minor typos in user module
|
||||
([#1289](https://github.com/lite-xl/lite-xl/pull/1289))
|
||||
|
||||
* Do not allow users to create an empty font group
|
||||
([#1303](https://github.com/lite-xl/lite-xl/pull/1303))
|
||||
|
||||
* Fix a memory leak
|
||||
([#1305](https://github.com/lite-xl/lite-xl/pull/1305))
|
||||
|
||||
* Make dirwatch sorting compatible with what file_bisect expects
|
||||
([#1300](https://github.com/lite-xl/lite-xl/pull/1300))
|
||||
|
||||
* Handle readlink errors
|
||||
([#1292](https://github.com/lite-xl/lite-xl/pull/1292))
|
||||
|
||||
* Disable horizontal scrolling when linewrapping is enabled
|
||||
([#1309](https://github.com/lite-xl/lite-xl/pull/1309))
|
||||
|
||||
* Update widgets install location
|
||||
|
||||
* Add missing luaL_typeerror symbol to plugin API
|
||||
([#1313](https://github.com/lite-xl/lite-xl/pull/1313))
|
||||
|
||||
* Defer lua error until after cleanup
|
||||
([#1310](https://github.com/lite-xl/lite-xl/pull/1310))
|
||||
|
||||
* Make empty groups in regex.gmatch return their offset
|
||||
([#1325](https://github.com/lite-xl/lite-xl/pull/1325))
|
||||
|
||||
* Add missing header declaration
|
||||
|
||||
* Fix msys build now requiring ca-certificates
|
||||
([#1348](https://github.com/lite-xl/lite-xl/pull/1348))
|
||||
|
||||
* Fix path to macOS arm64 cross file in GitHub workflows
|
||||
|
||||
* Fix Doc contextmenu not registering commands if scale plugin is not found
|
||||
([#1338](https://github.com/lite-xl/lite-xl/pull/1338))
|
||||
|
||||
* Fix TreeView contextmenu commands not working if the mouse hovers DocView
|
||||
([#1338](https://github.com/lite-xl/lite-xl/pull/1338))
|
||||
|
||||
* Fix incorrect contextmenu predicate
|
||||
([#1338](https://github.com/lite-xl/lite-xl/pull/1338))
|
||||
|
||||
* Properly rescale NagView on scale change
|
||||
([#1379](https://github.com/lite-xl/lite-xl/pull/1379))
|
||||
|
||||
* Scale plugin also rescales `style.expanded_scrollbar_size`
|
||||
([#1380](https://github.com/lite-xl/lite-xl/pull/1380))
|
||||
|
||||
* Improve DocView:get_visible_line_range precision
|
||||
([#1382](https://github.com/lite-xl/lite-xl/pull/1382))
|
||||
|
||||
* Fix up some post 5.1/JIT Symbols
|
||||
([#1385](https://github.com/lite-xl/lite-xl/pull/1385))
|
||||
|
||||
* Fix incorrect x_offset if opened docs have different tab sizes
|
||||
([#1383](https://github.com/lite-xl/lite-xl/pull/1383))
|
||||
|
||||
* Use correct view for scrolling to find-replace:repeat-find results
|
||||
([#1400](https://github.com/lite-xl/lite-xl/pull/1400))
|
||||
|
||||
* Improve text width calculation precision
|
||||
([#1408](https://github.com/lite-xl/lite-xl/pull/1408))
|
||||
|
||||
* Add asynchronous process reaping
|
||||
([#1412](https://github.com/lite-xl/lite-xl/pull/1412))
|
||||
|
||||
* Fix cursors positions when deleting multiple selections
|
||||
([#1393](https://github.com/lite-xl/lite-xl/pull/1393),
|
||||
[#1463](https://github.com/lite-xl/lite-xl/pull/1463))
|
||||
|
||||
* Fix invalid EXEFILE and EXEDIR on Windows
|
||||
([#1396](https://github.com/lite-xl/lite-xl/pull/1396))
|
||||
|
||||
* Fix `os.getenv()` not supporting UTF-8 output
|
||||
([#1397](https://github.com/lite-xl/lite-xl/pull/1397))
|
||||
|
||||
* Fix differing stacktrace on stdout and file
|
||||
([#1404](https://github.com/lite-xl/lite-xl/pull/1404))
|
||||
|
||||
* Update api_require to expose more symbols
|
||||
([#1437](https://github.com/lite-xl/lite-xl/pull/1437))
|
||||
|
||||
* Make system.path_compare more case-aware
|
||||
([#1457](https://github.com/lite-xl/lite-xl/pull/1457))
|
||||
|
||||
* Fix for api_require wrong macro && conditions
|
||||
([#1465](https://github.com/lite-xl/lite-xl/pull/1465))
|
||||
|
||||
* Merge carets after doc:move-to-{previous,next}-char
|
||||
([#1462](https://github.com/lite-xl/lite-xl/pull/1462))
|
||||
|
||||
* Process API improvements (again)
|
||||
([#1370](https://github.com/lite-xl/lite-xl/pull/1370))
|
||||
|
||||
* Make system.path_compare more digit-aware
|
||||
([#1474](https://github.com/lite-xl/lite-xl/pull/1474))
|
||||
|
||||
* Check for HANDLE_INVALID in Process API
|
||||
([#1475](https://github.com/lite-xl/lite-xl/pull/1475))
|
||||
|
||||
* Fix linewrapping bug to do with wordwrapping
|
||||
|
||||
* Fix compiler warning for printing size_t in rencache.c
|
||||
|
||||
* Return error string from C searcher
|
||||
|
||||
* Restore horizontal scroll position after scale change
|
||||
([#494](https://github.com/lite-xl/lite-xl/pull/494))
|
||||
|
||||
* Fix memory leak in renderer.c when freeing glyphsets
|
||||
|
||||
* Move lineguide below blinking cursor
|
||||
([#1511](https://github.com/lite-xl/lite-xl/pull/1511))
|
||||
|
||||
* Close lua state when exiting on a runtime error
|
||||
([#1487](https://github.com/lite-xl/lite-xl/pull/1487))
|
||||
|
||||
* Mark linewrapping open_files table as weak
|
||||
|
||||
* Don't use core.status_view if not yet initialized when logging
|
||||
|
||||
* Revert "core syntax: strip the path from filename on syntax.get ([#1168](https://github.com/lite-xl/lite-xl/pull/1168))"
|
||||
([#1322](https://github.com/lite-xl/lite-xl/pull/1322))
|
||||
|
||||
* Make Doc:sanitize_position return a more appropriate col
|
||||
([#1469](https://github.com/lite-xl/lite-xl/pull/1469))
|
||||
|
||||
* Skip checking files if no filename was provided to syntax.get
|
||||
|
||||
* Normalize stroke before adding keybind
|
||||
([#1334](https://github.com/lite-xl/lite-xl/pull/1334))
|
||||
|
||||
* Make DocView aware of scrollbars sizes
|
||||
([#1177](https://github.com/lite-xl/lite-xl/pull/1177))
|
||||
|
||||
* Normalize strokes in fixed order
|
||||
([#1572](https://github.com/lite-xl/lite-xl/pull/1572))
|
||||
|
||||
* Defer core:open-log until everything is loaded
|
||||
([#1585](https://github.com/lite-xl/lite-xl/pull/1585))
|
||||
|
||||
* Fix returned percent when clicking the Scrollbar track
|
||||
|
||||
* Fix C++14 digit separators
|
||||
([#1593](https://github.com/lite-xl/lite-xl/pull/1593))
|
||||
|
||||
* Make linewrapping consider the expanded Scrollbar size
|
||||
|
||||
* Fix dimmed text when antialiasing is turned off
|
||||
([#1641](https://github.com/lite-xl/lite-xl/pull/1641))
|
||||
|
||||
* Mark unsaved named files as dirty
|
||||
([#1598](https://github.com/lite-xl/lite-xl/pull/1598))
|
||||
|
||||
* Make `common.serialize()` locale-independent and nan/inf compatible
|
||||
([#1640](https://github.com/lite-xl/lite-xl/pull/1640))
|
||||
|
||||
* Ignore keypresses during IME composition
|
||||
([#1573](https://github.com/lite-xl/lite-xl/pull/1573))
|
||||
|
||||
* Fix deadlock if error handler jumps somewhere else
|
||||
([#1647](https://github.com/lite-xl/lite-xl/pull/1647))
|
||||
|
||||
* Avoid considering single spaces in detectindent
|
||||
([#1595](https://github.com/lite-xl/lite-xl/pull/1595))
|
||||
|
||||
* Fix deleting indentation with multiple cursors
|
||||
([#1670](https://github.com/lite-xl/lite-xl/pull/1670))
|
||||
|
||||
* Fix `set_target_size` passing the wrong value to plugins
|
||||
([#1657](https://github.com/lite-xl/lite-xl/pull/1657))
|
||||
|
||||
* Limit `system.{sleep,wait_event}` to `timeouts >= 0`
|
||||
([#1666](https://github.com/lite-xl/lite-xl/pull/1666))
|
||||
|
||||
* Fix running core.step when receiving an event while not waiting
|
||||
([#1667](https://github.com/lite-xl/lite-xl/pull/1667))
|
||||
|
||||
* Fix dirmonitor sorting issues
|
||||
([#1599](https://github.com/lite-xl/lite-xl/pull/1599))
|
||||
|
||||
* Scale mouse coordinates by window scale
|
||||
([#1630](https://github.com/lite-xl/lite-xl/pull/1630))
|
||||
|
||||
* Made coroutines make more sense, and fixed a bug
|
||||
([#1381](https://github.com/lite-xl/lite-xl/pull/1381))
|
||||
|
||||
* Fix selecting newlines with `find-replace:select-add-{next,all}`
|
||||
([#1608](https://github.com/lite-xl/lite-xl/pull/1608))
|
||||
|
||||
* Fix editing after undo not clearing the change id
|
||||
([#1574](https://github.com/lite-xl/lite-xl/pull/1574))
|
||||
|
||||
* Fix language_js regex constant detection
|
||||
([#1581](https://github.com/lite-xl/lite-xl/pull/1581))
|
||||
|
||||
* Fix patterns starting with `^` in tokenizer
|
||||
([#1645](https://github.com/lite-xl/lite-xl/pull/1645))
|
||||
|
||||
* Use x offset to define render command rect in rencache_draw_text
|
||||
([#1618](https://github.com/lite-xl/lite-xl/pull/1618))
|
||||
|
||||
* Improve font/color change detection in `language_md`
|
||||
([#1614](https://github.com/lite-xl/lite-xl/pull/1614))
|
||||
|
||||
* Allow long commands and envs on process_start
|
||||
([#1477](https://github.com/lite-xl/lite-xl/pull/1477))
|
||||
|
||||
* Fix typo in `drawwhitespace.lua`
|
||||
|
||||
* Fix NagBar save failed message
|
||||
([#1678](https://github.com/lite-xl/lite-xl/pull/1678))
|
||||
|
||||
* Fix typo in `drawwhitespace.lua`
|
||||
|
||||
* Add autocompletion to multicursor
|
||||
([#1394](https://github.com/lite-xl/lite-xl/pull/1394))
|
||||
|
||||
### Other Changes
|
||||
|
||||
* Make api_require's nodes const
|
||||
([#1296](https://github.com/lite-xl/lite-xl/pull/1296))
|
||||
|
||||
* Don't set a value twice
|
||||
([#1306](https://github.com/lite-xl/lite-xl/pull/1306))
|
||||
|
||||
* Center title and version in emptyview
|
||||
([#1311](https://github.com/lite-xl/lite-xl/pull/1311))
|
||||
|
||||
* Use master branch for packaging plugins for addons release
|
||||
|
||||
* Reorganize resources folder and add wasm target
|
||||
([#1244](https://github.com/lite-xl/lite-xl/pull/1244))
|
||||
|
||||
* Replace uses of SDL_Window with RenWindow
|
||||
([#1319](https://github.com/lite-xl/lite-xl/pull/1319))
|
||||
|
||||
* Update dummy dirmonitor method signature to match prototypes
|
||||
|
||||
* Remove static libgcc from meson
|
||||
([#1290](https://github.com/lite-xl/lite-xl/pull/1290))
|
||||
|
||||
* Pass RenWindow by argument
|
||||
([#1321](https://github.com/lite-xl/lite-xl/pull/1321))
|
||||
|
||||
* Get rid of annoying forward slash on windows
|
||||
([#1345](https://github.com/lite-xl/lite-xl/pull/1345))
|
||||
|
||||
* Improve plugins config table handling
|
||||
([#1356](https://github.com/lite-xl/lite-xl/pull/1356))
|
||||
|
||||
* Add manifest on Windows
|
||||
([#1405](https://github.com/lite-xl/lite-xl/pull/1405))
|
||||
|
||||
* Split Command struct into different structs for each command type
|
||||
([#1407](https://github.com/lite-xl/lite-xl/pull/1407))
|
||||
|
||||
* Move SetProcessDPIAware to manifests
|
||||
([#1413](https://github.com/lite-xl/lite-xl/pull/1413))
|
||||
|
||||
* Use clipping functions provided by SDL
|
||||
([#1426](https://github.com/lite-xl/lite-xl/pull/1426))
|
||||
|
||||
* Aggregate SDL_Surfaces and their scale in RenSurface
|
||||
([#1429](https://github.com/lite-xl/lite-xl/pull/1429))
|
||||
|
||||
* Disable trimwhitespace and drawwhitespace via their configs
|
||||
([#1446](https://github.com/lite-xl/lite-xl/pull/1446))
|
||||
|
||||
* Bump dependency versions
|
||||
([#1434](https://github.com/lite-xl/lite-xl/pull/1434))
|
||||
|
||||
* Improvements to cross-compilation
|
||||
([#1458](https://github.com/lite-xl/lite-xl/pull/1458))
|
||||
|
||||
* Move native plugin API header into include/
|
||||
([#1440](https://github.com/lite-xl/lite-xl/pull/1440))
|
||||
|
||||
* Build releases with Ubuntu 18.04 container
|
||||
([#1460](https://github.com/lite-xl/lite-xl/pull/1460))
|
||||
|
||||
* Update GitHub Actions dependencies
|
||||
|
||||
* Make all parameters for set_window_hit_test optional in documentation
|
||||
|
||||
* Attach command buffer to Renderer Window
|
||||
([#1472](https://github.com/lite-xl/lite-xl/pull/1472))
|
||||
|
||||
* Fix comment typo in object.lua
|
||||
([#1541](https://github.com/lite-xl/lite-xl/pull/1541))
|
||||
|
||||
* Allow setting custom glyphset size
|
||||
([#1542](https://github.com/lite-xl/lite-xl/pull/1542))
|
||||
|
||||
* Use FreeType header names in renderer.c
|
||||
([#1554](https://github.com/lite-xl/lite-xl/pull/1554))
|
||||
|
||||
* Add documentation for core.common
|
||||
([#1510](https://github.com/lite-xl/lite-xl/pull/1510))
|
||||
|
||||
* Document missing parameter for system.path_compare
|
||||
([#1566](https://github.com/lite-xl/lite-xl/pull/1566))
|
||||
|
||||
* Add documentation for core.command
|
||||
([#1564](https://github.com/lite-xl/lite-xl/pull/1564))
|
||||
|
||||
* Update the *Installing prebuild* section in README.md
|
||||
([#1548](https://github.com/lite-xl/lite-xl/pull/1548))
|
||||
|
||||
* Update README.md to remove previously installed files
|
||||
prior to installing a new version
|
||||
|
||||
* Use lite-xl Build Box to build releases
|
||||
([#1571](https://github.com/lite-xl/lite-xl/pull/1571))
|
||||
|
||||
* Use Lua wrap by default
|
||||
([#1481](https://github.com/lite-xl/lite-xl/pull/1481))
|
||||
|
||||
* Add documentation for contextmenu
|
||||
([#1567](https://github.com/lite-xl/lite-xl/pull/1567))
|
||||
|
||||
* Use dmgbuild to create DMGs
|
||||
([#1664](https://github.com/lite-xl/lite-xl/pull/1664))
|
||||
|
||||
* Un-hardcode lua subproject detection and update dependencies
|
||||
([#1676](https://github.com/lite-xl/lite-xl/pull/1676))
|
||||
|
||||
* Make license time-independent
|
||||
([#1655](https://github.com/lite-xl/lite-xl/pull/1655))
|
||||
|
||||
## [2.1.1] - 2022-12-29
|
||||
|
||||
### New Features
|
||||
|
@ -1004,6 +1504,9 @@ A new global variable `USERDIR` is exposed to point to the user's directory.
|
|||
|
||||
- subpixel font rendering with gamma correction
|
||||
|
||||
[2.1.4]: https://github.com/lite-xl/lite-xl/releases/tag/v2.1.4
|
||||
[2.1.3]: https://github.com/lite-xl/lite-xl/releases/tag/v2.1.3
|
||||
[2.1.2]: https://github.com/lite-xl/lite-xl/releases/tag/v2.1.2
|
||||
[2.1.1]: https://github.com/lite-xl/lite-xl/releases/tag/v2.1.1
|
||||
[2.1.0]: https://github.com/lite-xl/lite-xl/releases/tag/v2.1.0
|
||||
[2.0.5]: https://github.com/lite-xl/lite-xl/releases/tag/v2.0.5
|
||||
|
|
|
@ -185,7 +185,7 @@ command.add(nil, {
|
|||
local dirname = common.dirname(core.project_dir)
|
||||
local text
|
||||
if dirname then
|
||||
text = common.home_encode(dirname) .. PATHSEP
|
||||
text = common.basepath(common.home_encode(dirname))
|
||||
end
|
||||
core.command_view:enter("Change Project Folder", {
|
||||
text = text,
|
||||
|
|
|
@ -44,8 +44,8 @@ local function save(filename)
|
|||
else
|
||||
core.error(err)
|
||||
core.nag_view:show("Saving failed", string.format("Couldn't save file \"%s\". Do you want to save to another location?", doc().filename), {
|
||||
{ text = "No", default_no = true },
|
||||
{ text = "Yes", default_yes = true }
|
||||
{ text = "Yes", default_yes = true },
|
||||
{ text = "No", default_no = true }
|
||||
}, function(item)
|
||||
if item.text == "Yes" then
|
||||
core.add_thread(function()
|
||||
|
@ -93,11 +93,14 @@ local function cut_or_copy(delete)
|
|||
system.set_clipboard(full_text)
|
||||
end
|
||||
|
||||
local function split_cursor(direction)
|
||||
local function split_cursor(dv, direction)
|
||||
local new_cursors = {}
|
||||
for _, line1, col1 in doc():get_selections() do
|
||||
if line1 + direction >= 1 and line1 + direction <= #doc().lines then
|
||||
table.insert(new_cursors, { line1 + direction, col1 })
|
||||
local dv_translate = direction < 0
|
||||
and DocView.translate.previous_line
|
||||
or DocView.translate.next_line
|
||||
for _, line1, col1 in dv.doc:get_selections() do
|
||||
if line1 + direction >= 1 and line1 + direction <= #dv.doc.lines then
|
||||
table.insert(new_cursors, { dv_translate(dv.doc, line1, col1, dv) })
|
||||
end
|
||||
end
|
||||
-- add selections in the order that will leave the "last" added one as doc.last_selection
|
||||
|
@ -107,7 +110,7 @@ local function split_cursor(direction)
|
|||
end
|
||||
for i = start, stop, direction do
|
||||
local v = new_cursors[i]
|
||||
doc():add_selection(v[1], v[2])
|
||||
dv.doc:add_selection(v[1], v[2])
|
||||
end
|
||||
core.blink_reset()
|
||||
end
|
||||
|
@ -360,7 +363,7 @@ local commands = {
|
|||
["doc:select-lines"] = function(dv)
|
||||
for idx, line1, _, line2 in dv.doc:get_selections(true) do
|
||||
append_line_if_last_line(line2)
|
||||
dv.doc:set_selections(idx, line2 + 1, 1, line1, 1)
|
||||
dv.doc:set_selections(idx, line1, 1, line2 + 1, 1)
|
||||
end
|
||||
end,
|
||||
|
||||
|
@ -545,11 +548,6 @@ local commands = {
|
|||
dv.doc.crlf = not dv.doc.crlf
|
||||
end,
|
||||
|
||||
["doc:toggle-overwrite"] = function(dv)
|
||||
dv.doc.overwrite = not dv.doc.overwrite
|
||||
core.blink_reset() -- to show the cursor has changed edit modes
|
||||
end,
|
||||
|
||||
["doc:save-as"] = function(dv)
|
||||
local last_doc = core.last_active_view and core.last_active_view.doc
|
||||
local text
|
||||
|
@ -626,12 +624,12 @@ local commands = {
|
|||
end,
|
||||
|
||||
["doc:create-cursor-previous-line"] = function(dv)
|
||||
split_cursor(-1)
|
||||
split_cursor(dv, -1)
|
||||
dv.doc:merge_cursors()
|
||||
end,
|
||||
|
||||
["doc:create-cursor-next-line"] = function(dv)
|
||||
split_cursor(1)
|
||||
split_cursor(dv, 1)
|
||||
dv.doc:merge_cursors()
|
||||
end
|
||||
|
||||
|
|
|
@ -196,23 +196,6 @@ local function select_next(reverse)
|
|||
if l2 then doc():set_selection(l2, c2, l1, c1) end
|
||||
end
|
||||
|
||||
---@param in_selection? boolean whether to replace in the selections only, or in the whole file.
|
||||
local function find_replace(in_selection)
|
||||
local l1, c1, l2, c2 = doc():get_selection()
|
||||
local selected_text = ""
|
||||
if not in_selection then
|
||||
selected_text = doc():get_text(l1, c1, l2, c2)
|
||||
doc():set_selection(l2, c2, l2, c2)
|
||||
end
|
||||
replace("Text", l1 == l2 and selected_text or "", function(text, old, new)
|
||||
if not find_regex then
|
||||
return text:gsub(old:gsub("%W", "%%%1"), new:gsub("%%", "%%%%"), nil)
|
||||
end
|
||||
local result, matches = regex.gsub(regex.compile(old, "m"), text, new)
|
||||
return result, matches
|
||||
end)
|
||||
end
|
||||
|
||||
command.add(has_unique_selection, {
|
||||
["find-replace:select-next"] = select_next,
|
||||
["find-replace:select-previous"] = function() select_next(true) end,
|
||||
|
@ -229,11 +212,15 @@ command.add("core.docview!", {
|
|||
end,
|
||||
|
||||
["find-replace:replace"] = function()
|
||||
find_replace()
|
||||
end,
|
||||
|
||||
["find-replace:replace-in-selection"] = function()
|
||||
find_replace(true)
|
||||
local l1, c1, l2, c2 = doc():get_selection()
|
||||
local selected_text = doc():get_text(l1, c1, l2, c2)
|
||||
replace("Text", l1 == l2 and selected_text or "", function(text, old, new)
|
||||
if not find_regex then
|
||||
return text:gsub(old:gsub("%W", "%%%1"), new:gsub("%%", "%%%%"), nil)
|
||||
end
|
||||
local result, matches = regex.gsub(regex.compile(old, "m"), text, new)
|
||||
return result, matches
|
||||
end)
|
||||
end,
|
||||
|
||||
["find-replace:replace-symbol"] = function()
|
||||
|
|
|
@ -4,7 +4,6 @@ local DocView = require "core.docview"
|
|||
local command = require "core.command"
|
||||
local common = require "core.common"
|
||||
local config = require "core.config"
|
||||
local Node = require "core.node"
|
||||
|
||||
|
||||
local t = {
|
||||
|
@ -30,6 +29,20 @@ local t = {
|
|||
core.confirm_close_docs(docs, core.root_view.close_all_docviews, core.root_view, true)
|
||||
end,
|
||||
|
||||
["root:switch-to-previous-tab"] = function(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(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(node)
|
||||
local idx = node:get_view_idx(core.active_view)
|
||||
if idx > 1 then
|
||||
|
@ -104,7 +117,7 @@ end, t)
|
|||
|
||||
command.add(nil, {
|
||||
["root:scroll"] = function(delta)
|
||||
local view = core.root_view.overlapping_view or core.active_view
|
||||
local view = (core.root_view.overlapping_node and core.root_view.overlapping_node.active_view) or core.active_view
|
||||
if view and view.scrollable then
|
||||
view.scroll.to.y = view.scroll.to.y + delta * -config.mouse_wheel_scroll
|
||||
return true
|
||||
|
@ -112,7 +125,7 @@ command.add(nil, {
|
|||
return false
|
||||
end,
|
||||
["root:horizontal-scroll"] = function(delta)
|
||||
local view = core.root_view.overlapping_view or core.active_view
|
||||
local view = (core.root_view.overlapping_node and core.root_view.overlapping_node.active_view) or core.active_view
|
||||
if view and view.scrollable then
|
||||
view.scroll.to.x = view.scroll.to.x + delta * -config.mouse_wheel_scroll
|
||||
return true
|
||||
|
@ -120,74 +133,3 @@ command.add(nil, {
|
|||
return false
|
||||
end
|
||||
})
|
||||
|
||||
command.add(function(node)
|
||||
if not Node:is_extended_by(node) then node = nil end
|
||||
-- No node was specified, use the active one
|
||||
node = node or core.root_view:get_active_node()
|
||||
if not node then return false end
|
||||
return true, node
|
||||
end,
|
||||
{
|
||||
["root:switch-to-previous-tab"] = function(node)
|
||||
local idx = node:get_view_idx(node.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(node)
|
||||
local idx = node:get_view_idx(node.active_view)
|
||||
idx = idx + 1
|
||||
if idx > #node.views then idx = 1 end
|
||||
node:set_active_view(node.views[idx])
|
||||
end,
|
||||
|
||||
["root:scroll-tabs-backward"] = function(node)
|
||||
node:scroll_tabs(1)
|
||||
end,
|
||||
|
||||
["root:scroll-tabs-forward"] = function(node)
|
||||
node:scroll_tabs(2)
|
||||
end
|
||||
}
|
||||
)
|
||||
|
||||
command.add(function()
|
||||
local node = core.root_view.root_node:get_child_overlapping_point(core.root_view.mouse.x, core.root_view.mouse.y)
|
||||
if not node then return false end
|
||||
return (node.hovered_tab or node.hovered_scroll_button > 0) and true, node
|
||||
end,
|
||||
{
|
||||
["root:switch-to-hovered-previous-tab"] = function(node)
|
||||
command.perform("root:switch-to-previous-tab", node)
|
||||
end,
|
||||
|
||||
["root:switch-to-hovered-next-tab"] = function(node)
|
||||
command.perform("root:switch-to-next-tab", node)
|
||||
end,
|
||||
|
||||
["root:scroll-hovered-tabs-backward"] = function(node)
|
||||
command.perform("root:scroll-tabs-backward", node)
|
||||
end,
|
||||
|
||||
["root:scroll-hovered-tabs-forward"] = function(node)
|
||||
command.perform("root:scroll-tabs-forward", node)
|
||||
end
|
||||
}
|
||||
)
|
||||
|
||||
-- double clicking the tab bar, or on the emptyview should open a new doc
|
||||
command.add(function(x, y)
|
||||
local node = x and y and core.root_view.root_node:get_child_overlapping_point(x, y)
|
||||
return node and node:is_in_tab_area(x, y)
|
||||
end, {
|
||||
["tabbar:new-doc"] = function()
|
||||
command.perform("core:new-doc")
|
||||
end
|
||||
})
|
||||
command.add("core.emptyview", {
|
||||
["emptyview:new-doc"] = function()
|
||||
command.perform("core:new-doc")
|
||||
end
|
||||
})
|
||||
|
|
|
@ -50,6 +50,7 @@ local default_state = {
|
|||
function CommandView:new()
|
||||
CommandView.super.new(self, SingleLineDoc())
|
||||
self.suggestion_idx = 1
|
||||
self.suggestions_offset = 1
|
||||
self.suggestions = {}
|
||||
self.suggestions_height = 0
|
||||
self.last_change_id = 0
|
||||
|
@ -84,11 +85,6 @@ function CommandView:get_line_screen_position(line, col)
|
|||
end
|
||||
|
||||
|
||||
function CommandView:supports_text_input()
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function CommandView:get_scrollable_size()
|
||||
return 0
|
||||
end
|
||||
|
@ -128,6 +124,24 @@ function CommandView:move_suggestion_idx(dir)
|
|||
end
|
||||
end
|
||||
|
||||
local function get_suggestions_offset()
|
||||
local max_visible = math.min(max_suggestions, #self.suggestions)
|
||||
if dir > 0 then
|
||||
if self.suggestions_offset + max_visible < self.suggestion_idx + 1 then
|
||||
return self.suggestion_idx - max_visible + 1
|
||||
elseif self.suggestions_offset > self.suggestion_idx then
|
||||
return self.suggestion_idx
|
||||
end
|
||||
else
|
||||
if self.suggestions_offset > self.suggestion_idx then
|
||||
return self.suggestion_idx
|
||||
elseif self.suggestions_offset + max_visible < self.suggestion_idx + 1 then
|
||||
return self.suggestion_idx - max_visible + 1
|
||||
end
|
||||
end
|
||||
return self.suggestions_offset
|
||||
end
|
||||
|
||||
if self.state.show_suggestions then
|
||||
local n = self.suggestion_idx + dir
|
||||
self.suggestion_idx = overflow_suggestion_idx(n, #self.suggestions)
|
||||
|
@ -151,6 +165,8 @@ function CommandView:move_suggestion_idx(dir)
|
|||
self.last_change_id = self.doc:get_change_id()
|
||||
self.state.suggest(self:get_text())
|
||||
end
|
||||
|
||||
self.suggestions_offset = get_suggestions_offset()
|
||||
end
|
||||
|
||||
|
||||
|
@ -261,6 +277,7 @@ function CommandView:update_suggestions()
|
|||
end
|
||||
self.suggestions = res
|
||||
self.suggestion_idx = 1
|
||||
self.suggestions_offset = 1
|
||||
end
|
||||
|
||||
|
||||
|
@ -304,7 +321,7 @@ function CommandView:update()
|
|||
self:move_towards("suggestions_height", dest, nil, "commandview")
|
||||
|
||||
-- update suggestion cursor offset
|
||||
local dest = math.min(self.suggestion_idx, max_suggestions) * self:get_suggestion_line_height()
|
||||
local dest = (self.suggestion_idx - self.suggestions_offset + 1) * self:get_suggestion_line_height()
|
||||
self:move_towards("selection_offset", dest, nil, "commandview")
|
||||
|
||||
-- update size based on whether this is the active_view
|
||||
|
@ -340,6 +357,7 @@ local function draw_suggestions_box(self)
|
|||
local h = math.ceil(self.suggestions_height)
|
||||
local rx, ry, rw, rh = self.position.x, self.position.y - h - dh, self.size.x, h
|
||||
|
||||
core.push_clip_rect(rx, ry, rw, rh)
|
||||
-- draw suggestions background
|
||||
if #self.suggestions > 0 then
|
||||
renderer.draw_rect(rx, ry, rw, rh, style.background3)
|
||||
|
@ -349,14 +367,12 @@ local function draw_suggestions_box(self)
|
|||
end
|
||||
|
||||
-- draw suggestion text
|
||||
local offset = math.max(self.suggestion_idx - max_suggestions, 0)
|
||||
local last = math.min(offset + max_suggestions, #self.suggestions)
|
||||
core.push_clip_rect(rx, ry, rw, rh)
|
||||
local first = 1 + offset
|
||||
local first = math.max(self.suggestions_offset, 1)
|
||||
local last = math.min(self.suggestions_offset + max_suggestions, #self.suggestions)
|
||||
for i=first, last do
|
||||
local item = self.suggestions[i]
|
||||
local color = (i == self.suggestion_idx) and style.accent or style.text
|
||||
local y = self.position.y - (i - offset) * lh - dh
|
||||
local y = self.position.y - (i - first + 1) * lh - dh
|
||||
common.draw_text(self:get_font(), color, item.text, nil, x, y, 0, lh)
|
||||
|
||||
if item.info then
|
||||
|
|
|
@ -226,7 +226,13 @@ function common.path_suggest(text, root)
|
|||
if root and root:sub(-1) ~= PATHSEP then
|
||||
root = root .. PATHSEP
|
||||
end
|
||||
local path, name = text:match("^(.-)([^"..PATHSEP.."]*)$")
|
||||
local path, name
|
||||
if (PLATFORM == "AmigaOS 4" or PLATFORM == "MorphOS") then
|
||||
path, name = text:match("^(.-)([^:"..PATHSEP.."]*)$")
|
||||
else
|
||||
path, name = text:match("^(.-)([^"..PATHSEP.."]*)$")
|
||||
end
|
||||
|
||||
local clean_dotslash = false
|
||||
-- ignore root if path is absolute
|
||||
local is_absolute = common.is_absolute_path(text)
|
||||
|
@ -279,7 +285,12 @@ end
|
|||
---@param text string The input path.
|
||||
---@return string[]
|
||||
function common.dir_path_suggest(text)
|
||||
local path, name = text:match("^(.-)([^"..PATHSEP.."]*)$")
|
||||
local path, name
|
||||
if (PLATFORM == "AmigaOS 4" or PLATFORM == "MorphOS") then
|
||||
path, name = text:match("^(.-)([^:"..PATHSEP.."]*)$")
|
||||
else
|
||||
path, name = text:match("^(.-)([^"..PATHSEP.."]*)$")
|
||||
end
|
||||
local files = system.list_dir(path == "" and "." or path) or {}
|
||||
local res = {}
|
||||
for _, file in ipairs(files) do
|
||||
|
@ -298,7 +309,13 @@ end
|
|||
---@param dir_list string[] A list of paths to filter.
|
||||
---@return string[]
|
||||
function common.dir_list_suggest(text, dir_list)
|
||||
local path, name = text:match("^(.-)([^"..PATHSEP.."]*)$")
|
||||
local path, name
|
||||
if (PLATFORM == "AmigaOS 4" or PLATFORM == "MorphOS") then
|
||||
path, name = text:match("^(.-)([^:"..PATHSEP.."]*)$")
|
||||
else
|
||||
path, name = text:match("^(.-)([^"..PATHSEP.."]*)$")
|
||||
end
|
||||
|
||||
local res = {}
|
||||
for _, dir_path in ipairs(dir_list) do
|
||||
if dir_path:lower():find(text:lower(), nil, true) == 1 then
|
||||
|
@ -465,11 +482,35 @@ function common.basename(path)
|
|||
end
|
||||
|
||||
|
||||
---Returns the base path with the pathsep, if needed.
|
||||
---@param path string
|
||||
---@return string
|
||||
function common.basepath(path)
|
||||
-- Check for AmigaOS 4 and MorphOS if the last character is semicolon
|
||||
-- In these systems the volume name doesn't have a / or \ after the name
|
||||
-- but it is like VOLUME:
|
||||
if (PLATFORM == "AmigaOS 4" or PLATFORM == "MorphOS") and (string.sub(path, -1) == ":") then
|
||||
return path
|
||||
end
|
||||
return path .. PATHSEP
|
||||
end
|
||||
|
||||
|
||||
---Returns the directory name of a path.
|
||||
---If the path doesn't have a directory, this function may return nil.
|
||||
---@param path string
|
||||
---@return string|nil
|
||||
function common.dirname(path)
|
||||
if (PLATFORM == "AmigaOS 4" or PLATFORM == "MorphOS") then
|
||||
local drive, relpath = path:match('^([%w%s]*:)(.+)')
|
||||
if drive and relpath then
|
||||
local dir = relpath:match("(.+)["..PATHSEP.."][^"..PATHSEP.."]+$")
|
||||
if dir then
|
||||
return drive .. dir
|
||||
end
|
||||
end
|
||||
return path
|
||||
end
|
||||
return path:match("(.+)["..PATHSEP.."][^"..PATHSEP.."]+$")
|
||||
end
|
||||
|
||||
|
@ -507,6 +548,9 @@ end
|
|||
---@param text string
|
||||
---@return string
|
||||
function common.home_expand(text)
|
||||
if text == nil then
|
||||
return HOME
|
||||
end
|
||||
return HOME and text:gsub("^~", HOME) or text
|
||||
end
|
||||
|
||||
|
@ -516,6 +560,13 @@ local function split_on_slash(s, sep_pattern)
|
|||
if s:match("^["..PATHSEP.."]") then
|
||||
t[#t + 1] = ""
|
||||
end
|
||||
if (PLATFORM == "AmigaOS 4" or PLATFORM == "MorphOS") then
|
||||
local drive = s:match("^([%w%s]*:)")
|
||||
if drive then
|
||||
t[#t + 1] = ""
|
||||
s = s:gsub("^" .. drive, "")
|
||||
end
|
||||
end
|
||||
for fragment in string.gmatch(s, "([^"..PATHSEP.."]+)") do
|
||||
t[#t + 1] = fragment
|
||||
end
|
||||
|
@ -538,6 +589,12 @@ function common.normalize_volume(filename)
|
|||
return drive:upper() .. rem
|
||||
end
|
||||
end
|
||||
if (PLATFORM == "AmigaOS 4" or PLATFORM == "MorphOS") then
|
||||
local drive, rem = filename:match('^([%w%s]*:)(.-)' .. PATHSEP .. '?$')
|
||||
if drive then
|
||||
return drive .. rem
|
||||
end
|
||||
end
|
||||
return filename
|
||||
end
|
||||
|
||||
|
@ -563,6 +620,11 @@ function common.normalize_path(filename)
|
|||
volume, filename = drive, rem
|
||||
end
|
||||
end
|
||||
elseif (PLATFORM == "AmigaOS 4" or PLATFORM == "MorphOS") then
|
||||
local drive, relpath = filename:match('^([%w%s]*:)(.+)')
|
||||
if relpath then
|
||||
volume, filename = drive, relpath
|
||||
end
|
||||
else
|
||||
local relpath = filename:match('^/(.+)')
|
||||
if relpath then
|
||||
|
@ -593,7 +655,7 @@ end
|
|||
---@param path string
|
||||
---@return boolean
|
||||
function common.is_absolute_path(path)
|
||||
return path:sub(1, 1) == PATHSEP or path:match("^(%a):\\")
|
||||
return path:sub(1, 1) == PATHSEP or path:match("^(%a):\\") or path:match('^([%w%s]*):')
|
||||
end
|
||||
|
||||
|
||||
|
@ -602,7 +664,7 @@ end
|
|||
---@param path string The parent path.
|
||||
---@return boolean
|
||||
function common.path_belongs_to(filename, path)
|
||||
return string.find(filename, path .. PATHSEP, 1, true) == 1
|
||||
return string.find(filename, common.basepath(path), 1, true) == 1
|
||||
end
|
||||
|
||||
|
||||
|
@ -612,6 +674,9 @@ end
|
|||
---@return boolean
|
||||
function common.relative_path(ref_dir, dir)
|
||||
local drive_pattern = "^(%a):\\"
|
||||
if (PLATFORM == "AmigaOS 4" or PLATFORM == "MorphOS") then
|
||||
drive_pattern = "^([%w%s]*:)"
|
||||
end
|
||||
local drive, ref_drive = dir:match(drive_pattern), ref_dir:match(drive_pattern)
|
||||
if drive and ref_drive and drive ~= ref_drive then
|
||||
-- Windows, different drives, system.absolute_path fails for C:\..\D:\
|
||||
|
@ -654,7 +719,7 @@ function common.mkdirp(path)
|
|||
path = updir
|
||||
end
|
||||
for _, dirname in ipairs(subdirs) do
|
||||
path = path and path .. PATHSEP .. dirname or dirname
|
||||
path = path and common.basepath(path) .. dirname or dirname
|
||||
if not system.mkdir(path) then
|
||||
return false, "cannot create directory", path
|
||||
end
|
||||
|
|
|
@ -2,71 +2,15 @@ local common = require "core.common"
|
|||
|
||||
local config = {}
|
||||
|
||||
---The frame rate of Lite XL.
|
||||
---Note that setting this value to the screen's refresh rate
|
||||
---does not eliminate screen tearing.
|
||||
---
|
||||
---Defaults to 60.
|
||||
---@type number
|
||||
config.fps = 60
|
||||
|
||||
---Maximum number of log items that will be stored.
|
||||
---When the number of log items exceed this value, old items will be discarded.
|
||||
---
|
||||
---Defaults to 800.
|
||||
---@type number
|
||||
config.max_log_items = 800
|
||||
|
||||
---The timeout, in seconds, before a message dissapears from StatusView.
|
||||
---
|
||||
---Defaults to 5.
|
||||
---@type number
|
||||
config.message_timeout = 5
|
||||
|
||||
---The number of pixels scrolled per-step.
|
||||
---
|
||||
---Defaults to 50 * SCALE.
|
||||
---@type number
|
||||
config.mouse_wheel_scroll = 50 * SCALE
|
||||
|
||||
---Enables/disables transitions when scrolling with the scrollbar.
|
||||
---When enabled, the scrollbar will have inertia and slowly move towards the cursor.
|
||||
---Otherwise, the scrollbar will immediately follow the cursor.
|
||||
---
|
||||
---Defaults to false.
|
||||
---@type boolean
|
||||
config.animate_drag_scroll = false
|
||||
|
||||
---Enables/disables scrolling past the end of a document.
|
||||
---
|
||||
---Defaults to true.
|
||||
---@type boolean
|
||||
config.scroll_past_end = true
|
||||
|
||||
---@alias config.scrollbartype
|
||||
---| "expanded" # A thicker scrollbar is shown at all times.
|
||||
---| "contracted" # A thinner scrollbar is shown at all times.
|
||||
---| false # The scrollbar expands when the cursor hovers over it.
|
||||
|
||||
---Controls whether the DocView scrollbar is always shown or hidden.
|
||||
---This option does not affect other View's scrollbars.
|
||||
---
|
||||
---Defaults to false.
|
||||
---@type config.scrollbartype
|
||||
---@type "expanded" | "contracted" | false @Force the scrollbar status of the DocView
|
||||
config.force_scrollbar_status = false
|
||||
|
||||
---The file size limit, in megabytes.
|
||||
---Files larger than this size will not be shown in the file picker.
|
||||
---
|
||||
---Defaults to 10.
|
||||
---@type number
|
||||
config.file_size_limit = 10
|
||||
|
||||
---A list of files and directories to ignore.
|
||||
---Each element is a Lua pattern, where patterns ending with a forward slash
|
||||
---are recognized as directories while patterns ending with an anchor ("$") are
|
||||
---recognized as files.
|
||||
---@type string[]
|
||||
config.ignore_files = {
|
||||
-- folders
|
||||
"^%.svn/", "^%.git/", "^%.hg/", "^CVS/", "^%.Trash/", "^%.Trash%-.*/",
|
||||
|
@ -77,194 +21,46 @@ config.ignore_files = {
|
|||
"%.suo$", "%.pdb$", "%.idb$", "%.class$", "%.psd$", "%.db$",
|
||||
"^desktop%.ini$", "^%.DS_Store$", "^%.directory$",
|
||||
}
|
||||
|
||||
---Lua pattern used to find symbols when advanced syntax highlighting
|
||||
---is not available.
|
||||
---This pattern is also used for navigation, e.g. move to next word.
|
||||
---
|
||||
---The default pattern matches all letters, followed by any number
|
||||
---of letters and digits.
|
||||
---@type string
|
||||
config.symbol_pattern = "[%a_][%w_]*"
|
||||
|
||||
---A list of characters that delimits a word.
|
||||
---
|
||||
---The default is ``" \t\n/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-"``
|
||||
---@type string
|
||||
config.non_word_chars = " \t\n/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-"
|
||||
|
||||
---The timeout, in seconds, before several consecutive actions
|
||||
---are merged as a single undo step.
|
||||
---
|
||||
---The default is 0.3 seconds.
|
||||
---@type number
|
||||
config.undo_merge_timeout = 0.3
|
||||
|
||||
---The maximum number of undo steps per-document.
|
||||
---
|
||||
---The default is 10000.
|
||||
---@type number
|
||||
config.max_undos = 10000
|
||||
|
||||
---The maximum number of tabs shown at a time.
|
||||
---
|
||||
---The default is 8.
|
||||
---@type number
|
||||
config.max_tabs = 8
|
||||
|
||||
---Shows/hides the tab bar when there is only one tab open.
|
||||
---
|
||||
---The tab bar is always shown by default.
|
||||
---@type boolean
|
||||
config.always_show_tabs = true
|
||||
|
||||
---@alias config.highlightlinetype
|
||||
---| true # Always highlight the current line.
|
||||
---| false # Never highlight the current line.
|
||||
---| "no_selection" # Highlight the current line if no text is selected.
|
||||
|
||||
---Highlights the current line.
|
||||
---
|
||||
---The default is true.
|
||||
---@type config.highlightlinetype
|
||||
-- Possible values: false, true, "no_selection"
|
||||
config.highlight_current_line = true
|
||||
|
||||
---The spacing between each line of text.
|
||||
---
|
||||
---The default is 120% of the height of the text (1.2).
|
||||
---@type number
|
||||
config.line_height = 1.2
|
||||
|
||||
---The number of spaces each level of indentation represents.
|
||||
---
|
||||
---The default is 2.
|
||||
---@type number
|
||||
config.indent_size = 2
|
||||
|
||||
---The type of indentation.
|
||||
---
|
||||
---The default is "soft" (spaces).
|
||||
---@type "soft" | "hard"
|
||||
config.tab_type = "soft"
|
||||
|
||||
---Do not remove whitespaces when advancing to the next line.
|
||||
---
|
||||
---Defaults to false.
|
||||
---@type boolean
|
||||
config.keep_newline_whitespace = false
|
||||
|
||||
---Default line endings for new files.
|
||||
---
|
||||
---Defaults to `crlf` (`\r\n`) on Windows and `lf` (`\n`) on everything else.
|
||||
---@type "crlf" | "lf"
|
||||
config.line_endings = PLATFORM == "Windows" and "crlf" or "lf"
|
||||
|
||||
---Maximum number of characters per-line for the line guide.
|
||||
---
|
||||
---Defaults to 80.
|
||||
---@type number
|
||||
config.line_limit = 80
|
||||
|
||||
---Maximum number of project files to keep track of.
|
||||
---If the number of files in the project exceeds this number,
|
||||
---Lite XL will not be able to keep track of them.
|
||||
---They will be not be searched when searching for files or text.
|
||||
---
|
||||
---Defaults to 2000.
|
||||
---@type number
|
||||
config.max_project_files = 2000
|
||||
|
||||
---Enables/disables all transitions.
|
||||
---
|
||||
---Defaults to true.
|
||||
---@type boolean
|
||||
config.transitions = true
|
||||
|
||||
---Enable/disable individual transitions.
|
||||
---These values are overriden by `config.transitions`.
|
||||
config.disabled_transitions = {
|
||||
---Disables scrolling transitions.
|
||||
scroll = false,
|
||||
---Disables transitions for CommandView's suggestions list.
|
||||
commandview = false,
|
||||
---Disables transitions for showing/hiding the context menu.
|
||||
contextmenu = false,
|
||||
---Disables transitions when clicking on log items in LogView.
|
||||
logview = false,
|
||||
---Disables transitions for showing/hiding the Nagbar.
|
||||
nagbar = false,
|
||||
---Disables transitions when scrolling the tab bar.
|
||||
tabs = false,
|
||||
---Disables transitions when a tab is being dragged.
|
||||
tab_drag = false,
|
||||
---Disables transitions when a notification is shown.
|
||||
statusbar = false,
|
||||
}
|
||||
|
||||
---The rate of all transitions.
|
||||
---
|
||||
---Defaults to 1.
|
||||
---@type number
|
||||
config.animation_rate = 1.0
|
||||
|
||||
---The caret's blinking period, in seconds.
|
||||
---
|
||||
---Defaults to 0.8.
|
||||
---@type number
|
||||
config.blink_period = 0.8
|
||||
|
||||
---Disables caret blinking.
|
||||
---
|
||||
---Defaults to false.
|
||||
---@type boolean
|
||||
config.disable_blink = false
|
||||
|
||||
---Draws whitespaces as dots.
|
||||
---This option is deprecated.
|
||||
---Please use the drawwhitespace plugin instead.
|
||||
---@deprecated
|
||||
config.draw_whitespace = false
|
||||
|
||||
---Disables system-drawn window borders.
|
||||
---
|
||||
---When set to true, Lite XL draws its own window decorations,
|
||||
---which can be useful for certain setups.
|
||||
---
|
||||
---Defaults to false.
|
||||
---@type boolean
|
||||
config.borderless = false
|
||||
|
||||
---Shows/hides the close buttons on tabs.
|
||||
---When hidden, users can close tabs via keyboard shortcuts or commands.
|
||||
---
|
||||
---Defaults to true.
|
||||
---@type boolean
|
||||
config.tab_close_button = true
|
||||
|
||||
---Maximum number of clicks recognized by Lite XL.
|
||||
---
|
||||
---Defaults to 3.
|
||||
---@type number
|
||||
config.max_clicks = 3
|
||||
|
||||
---Disables plugin version checking.
|
||||
---Do not change this unless you know what you are doing.
|
||||
---
|
||||
---Defaults to false.
|
||||
---@type boolean
|
||||
-- set as true to be able to test non supported plugins
|
||||
config.skip_plugins_version = false
|
||||
|
||||
-- holds the plugins real config table
|
||||
local plugins_config = {}
|
||||
|
||||
---A table containing configuration for all the plugins.
|
||||
---
|
||||
---This is a metatable that automaticaly creates a minimal
|
||||
---configuration when a plugin is initially configured.
|
||||
---Each plugins will then call `common.merge()` to get the finalized
|
||||
---plugin config.
|
||||
---Do not use raw operations on this table.
|
||||
---@type table
|
||||
-- virtual representation of plugins config table
|
||||
config.plugins = {}
|
||||
|
||||
-- allows virtual access to the plugins config table
|
||||
|
|
|
@ -177,7 +177,8 @@ end
|
|||
-- compute a file's info entry completed with "filename" to be used
|
||||
-- in project scan or falsy if it shouldn't appear in the list.
|
||||
local function get_project_file_info(root, file, ignore_compiled)
|
||||
local info = system.get_file_info(root .. PATHSEP .. file)
|
||||
local info = system.get_file_info(common.basepath(root) .. file)
|
||||
|
||||
-- info can be not nil but info.type may be nil if is neither a file neither
|
||||
-- a directory, for example for /dev/* entries on linux.
|
||||
if info and info.type then
|
||||
|
@ -200,7 +201,8 @@ function dirwatch.get_directory_files(dir, root, path, entries_count, recurse_pr
|
|||
local t0 = system.get_time()
|
||||
local ignore_compiled = compile_ignore_files()
|
||||
|
||||
local all = system.list_dir(root .. PATHSEP .. path)
|
||||
local all = system.list_dir(common.basepath(root) .. path)
|
||||
|
||||
if not all then return nil end
|
||||
local entries = { }
|
||||
for _, file in ipairs(all) do
|
||||
|
|
|
@ -48,7 +48,7 @@ function Highlighter:start()
|
|||
self:update_notify(retokenized_from, max - retokenized_from)
|
||||
end
|
||||
core.redraw = true
|
||||
coroutine.yield(0)
|
||||
coroutine.yield()
|
||||
end
|
||||
self.max_wanted_line = 0
|
||||
self.running = false
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
local Object = require "core.object"
|
||||
local Highlighter = require "core.doc.highlighter"
|
||||
local translate = require "core.doc.translate"
|
||||
local core = require "core"
|
||||
local syntax = require "core.syntax"
|
||||
local config = require "core.config"
|
||||
|
@ -28,11 +27,9 @@ function Doc:new(filename, abs_filename, new_file)
|
|||
self:load(filename)
|
||||
end
|
||||
end
|
||||
if new_file then
|
||||
self.crlf = config.line_endings == "crlf"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function Doc:reset()
|
||||
self.lines = { "\n" }
|
||||
self.selections = { 1, 1, 1, 1 }
|
||||
|
@ -41,15 +38,15 @@ function Doc:reset()
|
|||
self.redo_stack = { idx = 1 }
|
||||
self.clean_change_id = 1
|
||||
self.highlighter = Highlighter(self)
|
||||
self.overwrite = false
|
||||
self:reset_syntax()
|
||||
end
|
||||
|
||||
|
||||
function Doc:reset_syntax()
|
||||
local header = self:get_text(1, 1, self:position_offset(1, 1, 128))
|
||||
local path = self.abs_filename
|
||||
if not path and self.filename then
|
||||
path = core.project_dir .. PATHSEP .. self.filename
|
||||
path = common.basepath(core.project_dir) .. self.filename
|
||||
end
|
||||
if path then path = common.normalize_path(path) end
|
||||
local syn = syntax.get(path, header)
|
||||
|
@ -59,14 +56,16 @@ function Doc:reset_syntax()
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
function Doc:set_filename(filename, abs_filename)
|
||||
self.filename = filename
|
||||
self.abs_filename = abs_filename
|
||||
self:reset_syntax()
|
||||
end
|
||||
|
||||
|
||||
function Doc:load(filename)
|
||||
local fp = assert(io.open(filename, "rb"))
|
||||
local fp = assert( io.open(filename, "rb") )
|
||||
self:reset()
|
||||
self.lines = {}
|
||||
local i = 1
|
||||
|
@ -86,6 +85,7 @@ function Doc:load(filename)
|
|||
self:reset_syntax()
|
||||
end
|
||||
|
||||
|
||||
function Doc:reload()
|
||||
if self.filename then
|
||||
local sel = { self:get_selection() }
|
||||
|
@ -95,6 +95,7 @@ function Doc:reload()
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
function Doc:save(filename, abs_filename)
|
||||
if not filename then
|
||||
assert(self.filename, "no filename set to default to")
|
||||
|
@ -103,7 +104,7 @@ function Doc:save(filename, abs_filename)
|
|||
else
|
||||
assert(self.filename or abs_filename, "calling save on unnamed doc without absolute path")
|
||||
end
|
||||
local fp = assert(io.open(filename, "wb"))
|
||||
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)
|
||||
|
@ -114,10 +115,12 @@ function Doc:save(filename, abs_filename)
|
|||
self:clean()
|
||||
end
|
||||
|
||||
|
||||
function Doc:get_name()
|
||||
return self.filename or "unsaved"
|
||||
end
|
||||
|
||||
|
||||
function Doc:is_dirty()
|
||||
if self.new_file then
|
||||
if self.filename then return true end
|
||||
|
@ -127,17 +130,20 @@ function Doc:is_dirty()
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
function Doc:clean()
|
||||
self.clean_change_id = self:get_change_id()
|
||||
end
|
||||
|
||||
|
||||
function Doc:get_indent_info()
|
||||
if not self.indent_info then return config.tab_type, config.indent_size, false end
|
||||
return self.indent_info.type or config.tab_type,
|
||||
self.indent_info.size or config.indent_size,
|
||||
self.indent_info.confirmed
|
||||
self.indent_info.size or config.indent_size,
|
||||
self.indent_info.confirmed
|
||||
end
|
||||
|
||||
|
||||
function Doc:get_change_id()
|
||||
return self.undo_stack.idx
|
||||
end
|
||||
|
@ -161,14 +167,13 @@ function Doc:get_selection(sort)
|
|||
return line1, col1, line2, col2, swap
|
||||
end
|
||||
|
||||
|
||||
---Get the selection specified by `idx`
|
||||
---@param idx integer @the index of the selection to retrieve
|
||||
---@param sort? boolean @whether to sort the selection returned
|
||||
---@return integer,integer,integer,integer,boolean? @line1, col1, line2, col2, was the selection sorted
|
||||
function Doc:get_selection_idx(idx, sort)
|
||||
local line1, col1, line2, col2 = self.selections[idx * 4 - 3], self.selections[idx * 4 - 2],
|
||||
self.selections[idx * 4 - 1],
|
||||
self.selections[idx * 4]
|
||||
local line1, col1, line2, col2 = self.selections[idx*4-3], self.selections[idx*4-2], self.selections[idx*4-1], self.selections[idx*4]
|
||||
if line1 and sort then
|
||||
return sort_positions(line1, col1, line2, col2)
|
||||
else
|
||||
|
@ -212,7 +217,7 @@ function Doc:set_selections(idx, line1, col1, line2, col2, swap, rm)
|
|||
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)
|
||||
common.splice(self.selections, (idx - 1) * 4 + 1, rm == nil and 4 or rm, { line1, col1, line2, col2 })
|
||||
common.splice(self.selections, (idx - 1)*4 + 1, rm == nil and 4 or rm, { line1, col1, line2, col2 })
|
||||
end
|
||||
|
||||
function Doc:add_selection(line1, col1, line2, col2, swap)
|
||||
|
@ -228,6 +233,7 @@ function Doc:add_selection(line1, col1, line2, col2, swap)
|
|||
self.last_selection = target
|
||||
end
|
||||
|
||||
|
||||
function Doc:remove_selection(idx)
|
||||
if self.last_selection >= idx then
|
||||
self.last_selection = self.last_selection - 1
|
||||
|
@ -235,6 +241,7 @@ function Doc:remove_selection(idx)
|
|||
common.splice(self.selections, (idx - 1) * 4 + 1, 4)
|
||||
end
|
||||
|
||||
|
||||
function Doc:set_selection(line1, col1, line2, col2, swap)
|
||||
self.selections = {}
|
||||
self:set_selections(1, line1, col1, line2, col2, swap)
|
||||
|
@ -245,24 +252,24 @@ function Doc:merge_cursors(idx)
|
|||
for i = (idx or (#self.selections - 3)), (idx or 5), -4 do
|
||||
for j = 1, i - 4, 4 do
|
||||
if self.selections[i] == self.selections[j] and
|
||||
self.selections[i + 1] == self.selections[j + 1] then
|
||||
common.splice(self.selections, i, 4)
|
||||
if self.last_selection >= (i + 3) / 4 then
|
||||
self.last_selection = self.last_selection - 1
|
||||
end
|
||||
break
|
||||
self.selections[i+1] == self.selections[j+1] then
|
||||
common.splice(self.selections, i, 4)
|
||||
if self.last_selection >= (i+3)/4 then
|
||||
self.last_selection = self.last_selection - 1
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function selection_iterator(invariant, idx)
|
||||
local target = invariant[3] and (idx * 4 - 7) or (idx * 4 + 1)
|
||||
local target = invariant[3] and (idx*4 - 7) or (idx*4 + 1)
|
||||
if target > #invariant[1] or target <= 0 or (type(invariant[3]) == "number" and invariant[3] ~= idx - 1) then return end
|
||||
if invariant[2] then
|
||||
return idx + (invariant[3] and -1 or 1), sort_positions(table.unpack(invariant[1], target, target + 4))
|
||||
return idx+(invariant[3] and -1 or 1), sort_positions(table.unpack(invariant[1], target, target+4))
|
||||
else
|
||||
return idx + (invariant[3] and -1 or 1), table.unpack(invariant[1], target, target + 4)
|
||||
return idx+(invariant[3] and -1 or 1), table.unpack(invariant[1], target, target+4)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -270,9 +277,8 @@ end
|
|||
-- If a number, runs for exactly that iteration.
|
||||
function Doc:get_selections(sort_intra, idx_reverse)
|
||||
return selection_iterator, { self.selections, sort_intra, idx_reverse },
|
||||
idx_reverse == true and ((#self.selections / 4) + 1) or ((idx_reverse or -1) + 1)
|
||||
idx_reverse == true and ((#self.selections / 4) + 1) or ((idx_reverse or -1)+1)
|
||||
end
|
||||
|
||||
-- End of cursor seciton.
|
||||
|
||||
function Doc:sanitize_position(line, col)
|
||||
|
@ -285,6 +291,7 @@ function Doc:sanitize_position(line, col)
|
|||
return line, common.clamp(col, 1, #self.lines[line])
|
||||
end
|
||||
|
||||
|
||||
local function position_offset_func(self, line, col, fn, ...)
|
||||
line, col = self:sanitize_position(line, col)
|
||||
return fn(self, line, col, ...)
|
||||
|
@ -323,6 +330,7 @@ function Doc:position_offset(line, col, ...)
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
function Doc:get_text(line1, col1, line2, col2)
|
||||
line1, col1 = self:sanitize_position(line1, col1)
|
||||
line2, col2 = self:sanitize_position(line2, col2)
|
||||
|
@ -338,11 +346,13 @@ function Doc:get_text(line1, col1, line2, col2)
|
|||
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
|
||||
|
@ -403,8 +413,7 @@ function Doc:raw_insert(line, col, text, undo_stack, time)
|
|||
if cline1 < line then break end
|
||||
local line_addition = (line < cline1 or col < ccol1) and #lines - 1 or 0
|
||||
local column_addition = line == cline1 and ccol1 > col and len or 0
|
||||
self:set_selections(idx, cline1 + line_addition, ccol1 + column_addition, cline2 + line_addition,
|
||||
ccol2 + column_addition)
|
||||
self:set_selections(idx, cline1 + line_addition, ccol1 + column_addition, cline2 + line_addition, ccol2 + column_addition)
|
||||
end
|
||||
|
||||
-- push undo
|
||||
|
@ -417,6 +426,7 @@ function Doc:raw_insert(line, col, text, undo_stack, time)
|
|||
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)
|
||||
|
@ -475,6 +485,7 @@ function Doc:raw_remove(line1, col1, line2, col2, undo_stack, time)
|
|||
self:sanitize_selection()
|
||||
end
|
||||
|
||||
|
||||
function Doc:insert(line, col, text)
|
||||
self.redo_stack = { idx = 1 }
|
||||
-- Reset the clean id when we're pushing something new before it
|
||||
|
@ -486,6 +497,7 @@ function Doc:insert(line, col, text)
|
|||
self:on_text_change("insert")
|
||||
end
|
||||
|
||||
|
||||
function Doc:remove(line1, col1, line2, col2)
|
||||
self.redo_stack = { idx = 1 }
|
||||
line1, col1 = self:sanitize_position(line1, col1)
|
||||
|
@ -495,34 +507,28 @@ function Doc:remove(line1, col1, line2, col2)
|
|||
self:on_text_change("remove")
|
||||
end
|
||||
|
||||
|
||||
function Doc:undo()
|
||||
pop_undo(self, self.undo_stack, self.redo_stack, false)
|
||||
end
|
||||
|
||||
|
||||
function Doc:redo()
|
||||
pop_undo(self, self.redo_stack, self.undo_stack, false)
|
||||
end
|
||||
|
||||
|
||||
function Doc:text_input(text, idx)
|
||||
for sidx, line1, col1, line2, col2 in self:get_selections(true, idx or true) do
|
||||
local had_selection = false
|
||||
if line1 ~= line2 or col1 ~= col2 then
|
||||
self:delete_to_cursor(sidx)
|
||||
had_selection = true
|
||||
end
|
||||
|
||||
if self.overwrite
|
||||
and not had_selection
|
||||
and col1 < #self.lines[line1]
|
||||
and text:ulen() == 1 then
|
||||
self:remove(line1, col1, translate.next_char(self, line1, col1))
|
||||
end
|
||||
|
||||
self:insert(line1, col1, text)
|
||||
self:move_to_cursor(sidx, #text)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function Doc:ime_text_editing(text, start, length, idx)
|
||||
for sidx, line1, col1, line2, col2 in self:get_selections(true, idx or true) do
|
||||
if line1 ~= line2 or col1 ~= col2 then
|
||||
|
@ -533,6 +539,7 @@ function Doc:ime_text_editing(text, start, length, idx)
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
function Doc:replace_cursor(idx, line1, col1, line2, col2, fn)
|
||||
local old_text = self:get_text(line1, col1, line2, col2)
|
||||
local new_text, res = fn(old_text)
|
||||
|
@ -548,7 +555,7 @@ function Doc:replace_cursor(idx, line1, col1, line2, col2, fn)
|
|||
end
|
||||
|
||||
function Doc:replace(fn)
|
||||
local has_selection, results = false, {}
|
||||
local has_selection, results = false, { }
|
||||
for idx, line1, col1, line2, col2 in self:get_selections(true) do
|
||||
if line1 ~= line2 or col1 ~= col2 then
|
||||
results[idx] = self:replace_cursor(idx, line1, col1, line2, col2, fn)
|
||||
|
@ -562,6 +569,7 @@ function Doc:replace(fn)
|
|||
return results
|
||||
end
|
||||
|
||||
|
||||
function Doc:delete_to_cursor(idx, ...)
|
||||
for sidx, line1, col1, line2, col2 in self:get_selections(true, idx) do
|
||||
if line1 ~= line2 or col1 ~= col2 then
|
||||
|
@ -575,7 +583,6 @@ function Doc:delete_to_cursor(idx, ...)
|
|||
end
|
||||
self:merge_cursors(idx)
|
||||
end
|
||||
|
||||
function Doc:delete_to(...) return self:delete_to_cursor(nil, ...) end
|
||||
|
||||
function Doc:move_to_cursor(idx, ...)
|
||||
|
@ -584,9 +591,9 @@ function Doc:move_to_cursor(idx, ...)
|
|||
end
|
||||
self:merge_cursors(idx)
|
||||
end
|
||||
|
||||
function Doc:move_to(...) return self:move_to_cursor(nil, ...) end
|
||||
|
||||
|
||||
function Doc:select_to_cursor(idx, ...)
|
||||
for sidx, line, col, line2, col2 in self:get_selections(false, idx) do
|
||||
line, col = self:position_offset(line, col, ...)
|
||||
|
@ -594,9 +601,9 @@ function Doc:select_to_cursor(idx, ...)
|
|||
end
|
||||
self:merge_cursors(idx)
|
||||
end
|
||||
|
||||
function Doc:select_to(...) return self:select_to_cursor(nil, ...) end
|
||||
|
||||
|
||||
function Doc:get_indent_string()
|
||||
local indent_type, indent_size = self:get_indent_info()
|
||||
if indent_type == "hard" then
|
||||
|
@ -618,7 +625,7 @@ function Doc:get_line_indent(line, rnd_up)
|
|||
local indent = e and line:sub(1, e):gsub("\t", soft_tab) or ""
|
||||
local number = #indent / #soft_tab
|
||||
return e, indent:sub(1,
|
||||
(rnd_up and math.ceil(number) or math.floor(number)) * #soft_tab)
|
||||
(rnd_up and math.ceil(number) or math.floor(number))*#soft_tab)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -667,4 +674,5 @@ function Doc:on_close()
|
|||
core.log_quiet("Closed doc \"%s\"", self:get_name())
|
||||
end
|
||||
|
||||
|
||||
return Doc
|
||||
|
|
|
@ -254,11 +254,6 @@ function DocView:scroll_to_line(line, ignore_if_visible, instant)
|
|||
end
|
||||
|
||||
|
||||
function DocView:supports_text_input()
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function DocView:scroll_to_make_visible(line, col)
|
||||
local _, oy = self:get_content_offset()
|
||||
local _, ly = self:get_line_screen_position(line, col)
|
||||
|
@ -322,7 +317,7 @@ function DocView:mouse_selection(doc, snap_type, line1, col1, line2, col2)
|
|||
line1, col1 = translate.start_of_word(doc, line1, col1)
|
||||
line2, col2 = translate.end_of_word(doc, line2, col2)
|
||||
elseif snap_type == "lines" then
|
||||
col1, col2, line2 = 1, 1, line2 + 1
|
||||
col1, col2 = 1, math.huge
|
||||
end
|
||||
if swap then
|
||||
return line2, col2, line1, col1
|
||||
|
@ -446,7 +441,7 @@ function DocView:draw_line_text(line, x, y)
|
|||
local last_token = nil
|
||||
local tokens = self.doc.highlighter:get_line(line).tokens
|
||||
local tokens_count = #tokens
|
||||
if string.sub(tokens[tokens_count], -1) == "\n" then
|
||||
if tokens[tokens_count] ~= nil and string.sub(tokens[tokens_count], -1) == "\n" then
|
||||
last_token = tokens_count - 1
|
||||
end
|
||||
for tidx, type, text in self.doc.highlighter:each_token(line) do
|
||||
|
@ -460,16 +455,9 @@ function DocView:draw_line_text(line, x, y)
|
|||
return self:get_line_height()
|
||||
end
|
||||
|
||||
|
||||
function DocView:draw_overwrite_caret(x, y, width)
|
||||
local lh = self:get_line_height()
|
||||
renderer.draw_rect(x, y + lh - style.caret_width, width, style.caret_width, style.caret)
|
||||
end
|
||||
|
||||
|
||||
function DocView:draw_caret(x, y)
|
||||
local lh = self:get_line_height()
|
||||
renderer.draw_rect(x, y, style.caret_width, lh, style.caret)
|
||||
local lh = self:get_line_height()
|
||||
renderer.draw_rect(x, y, style.caret_width, lh, style.caret)
|
||||
end
|
||||
|
||||
function DocView:draw_line_body(line, x, y)
|
||||
|
@ -566,12 +554,7 @@ function DocView:draw_overlay()
|
|||
else
|
||||
if config.disable_blink
|
||||
or (core.blink_timer - core.blink_start) % T < T / 2 then
|
||||
local x, y = self:get_line_screen_position(line1, col1)
|
||||
if self.doc.overwrite then
|
||||
self:draw_overwrite_caret(x, y, self:get_font():get_width(self.doc:get_char(line1, col1)))
|
||||
else
|
||||
self:draw_caret(x, y)
|
||||
end
|
||||
self:draw_caret(self:get_line_screen_position(line1, col1))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -18,13 +18,13 @@ local Doc
|
|||
local core = {}
|
||||
|
||||
local function load_session()
|
||||
local ok, t = pcall(dofile, USERDIR .. PATHSEP .. "session.lua")
|
||||
local ok, t = pcall(dofile, common.basepath(USERDIR) .. "session.lua")
|
||||
return ok and t or {}
|
||||
end
|
||||
|
||||
|
||||
local function save_session()
|
||||
local fp = io.open(USERDIR .. PATHSEP .. "session.lua", "w")
|
||||
local fp = io.open(common.basepath(USERDIR) .. "session.lua", "w")
|
||||
if fp then
|
||||
fp:write("return {recents=", common.serialize(core.recent_projects),
|
||||
", window=", common.serialize(table.pack(system.get_window_size())),
|
||||
|
@ -188,7 +188,7 @@ local function refresh_directory(topdir, target)
|
|||
-- If this file doesn't exist, we should be calling this on our parent directory, assume we'll do that.
|
||||
-- Unwatch just in case.
|
||||
if files == nil then
|
||||
topdir.watch:unwatch(topdir.name .. PATHSEP .. (target or ""))
|
||||
topdir.watch:unwatch(common.basepath(topdir.name) .. (target or ""))
|
||||
return true
|
||||
end
|
||||
|
||||
|
@ -212,7 +212,7 @@ local function refresh_directory(topdir, target)
|
|||
-- If it's not there, remove the entry from the list as being out of order.
|
||||
table.remove(topdir.files, old_idx)
|
||||
if old_info.type == "dir" then
|
||||
topdir.watch:unwatch(topdir.name .. PATHSEP .. old_info.filename)
|
||||
topdir.watch:unwatch(common.basepath(topdir.name) .. old_info.filename)
|
||||
end
|
||||
directory_end_idx = directory_end_idx - 1
|
||||
end
|
||||
|
@ -223,7 +223,7 @@ local function refresh_directory(topdir, target)
|
|||
end
|
||||
end
|
||||
for i, v in ipairs(new_directories) do
|
||||
topdir.watch:watch(topdir.name .. PATHSEP .. v.filename)
|
||||
topdir.watch:watch(common.basepath(topdir.name) .. v.filename)
|
||||
if not topdir.files_limit or core.project_subdir_is_shown(topdir, v.filename) then
|
||||
refresh_directory(topdir, v.filename)
|
||||
end
|
||||
|
@ -272,7 +272,7 @@ function core.add_project_directory(path)
|
|||
refresh_directory(topdir)
|
||||
else
|
||||
for i,v in ipairs(t) do
|
||||
if v.type == "dir" then topdir.watch:watch(path .. PATHSEP .. v.filename) end
|
||||
if v.type == "dir" then topdir.watch:watch(common.basepath(path) .. v.filename) end
|
||||
end
|
||||
end
|
||||
topdir.watch:watch(topdir.name)
|
||||
|
@ -286,7 +286,7 @@ function core.add_project_directory(path)
|
|||
local changed = topdir.watch:check(function(target)
|
||||
if target == topdir.name then return refresh_directory(topdir) end
|
||||
local dirpath = target:sub(#topdir.name + 2)
|
||||
local abs_dirpath = topdir.name .. PATHSEP .. dirpath
|
||||
local abs_dirpath = common.basepath(topdir.name) .. dirpath
|
||||
if dirpath then
|
||||
-- check if the directory is in the project files list, if not exit.
|
||||
local dir_index, dir_match = file_search(topdir.files, {filename = dirpath, type = "dir"})
|
||||
|
@ -373,9 +373,9 @@ function core.update_project_subdir(dir, filename, expanded)
|
|||
assert(dir.files_limit, "function should be called only when directory is in files limit mode")
|
||||
dir.shown_subdir[filename] = expanded
|
||||
if expanded then
|
||||
dir.watch:watch(dir.name .. PATHSEP .. filename)
|
||||
dir.watch:watch(common.basepath(dir.name) .. filename)
|
||||
else
|
||||
dir.watch:unwatch(dir.name .. PATHSEP .. filename)
|
||||
dir.watch:unwatch(common.basepath(dir.name) .. filename)
|
||||
end
|
||||
return refresh_directory(dir, filename)
|
||||
end
|
||||
|
@ -387,7 +387,7 @@ end
|
|||
local function find_files_rec(root, path)
|
||||
local all = system.list_dir(root .. path) or {}
|
||||
for _, file in ipairs(all) do
|
||||
local file = path .. PATHSEP .. file
|
||||
local file = common.basepath(path) .. file
|
||||
local info = system.get_file_info(root .. file)
|
||||
if info then
|
||||
info.filename = strip_leading_path(file)
|
||||
|
@ -462,7 +462,7 @@ local function create_user_directory()
|
|||
error("cannot create directory \"" .. USERDIR .. "\": " .. err)
|
||||
end
|
||||
for _, modname in ipairs {'plugins', 'colors', 'fonts'} do
|
||||
local subdirname = USERDIR .. PATHSEP .. modname
|
||||
local subdirname = common.basepath(USERDIR) .. modname
|
||||
if not system.mkdir(subdirname) then
|
||||
error("cannot create directory: \"" .. subdirname .. "\"")
|
||||
end
|
||||
|
@ -572,22 +572,22 @@ local config = require "core.config"
|
|||
--
|
||||
-- Here some examples:
|
||||
--
|
||||
-- "^%." match any file of directory whose basename begins with a dot.
|
||||
-- "^%." matches any file of directory whose basename begins with a dot.
|
||||
--
|
||||
-- When there is an '/' or a '/$' at the end the pattern it will only match
|
||||
-- When there is an '/' or a '/$' at the end, the pattern will only match
|
||||
-- directories. When using such a pattern a final '/' will be added to the name
|
||||
-- of any directory entry before checking if it matches.
|
||||
--
|
||||
-- "^%.git/" matches any directory named ".git" anywhere in the project.
|
||||
--
|
||||
-- If a "/" appears anywhere in the pattern except if it appears at the end or
|
||||
-- is immediately followed by a '$' then the pattern will be applied to the full
|
||||
-- If a "/" appears anywhere in the pattern (except when it appears at the end or
|
||||
-- is immediately followed by a '$'), then the pattern will be applied to the full
|
||||
-- path of the file or directory. An initial "/" will be prepended to the file's
|
||||
-- or directory's path to indicate the project's root.
|
||||
--
|
||||
-- "^/node_modules/" will match a directory named "node_modules" at the project's root.
|
||||
-- "^/build.*/" match any top level directory whose name begins with "build"
|
||||
-- "^/subprojects/.+/" match any directory inside a top-level folder named "subprojects".
|
||||
-- "^/build.*/" will match any top level directory whose name begins with "build".
|
||||
-- "^/subprojects/.+/" will match any directory inside a top-level folder named "subprojects".
|
||||
|
||||
-- You may activate some plugins on a per-project basis to override the user's settings.
|
||||
-- config.plugins.trimwitespace = true
|
||||
|
@ -602,7 +602,7 @@ function core.load_user_directory()
|
|||
if not stat_dir then
|
||||
create_user_directory()
|
||||
end
|
||||
local init_filename = USERDIR .. PATHSEP .. "init.lua"
|
||||
local init_filename = common.basepath(USERDIR) .. "init.lua"
|
||||
local stat_file = system.get_file_info(init_filename)
|
||||
if not stat_file then
|
||||
write_user_init_file(init_filename)
|
||||
|
@ -635,7 +635,7 @@ end
|
|||
local function add_config_files_hooks()
|
||||
-- auto-realod style when user's module is saved by overriding Doc:Save()
|
||||
local doc_save = Doc.save
|
||||
local user_filename = system.absolute_path(USERDIR .. PATHSEP .. "init.lua")
|
||||
local user_filename = system.absolute_path(common.basepath(USERDIR) .. "init.lua")
|
||||
function Doc:save(filename, abs_filename)
|
||||
local module_filename = system.absolute_path(".lite_project.lua")
|
||||
doc_save(self, filename, abs_filename)
|
||||
|
@ -660,17 +660,14 @@ function core.project_absolute_path(filename)
|
|||
return common.normalize_path(filename)
|
||||
elseif not core.project_dir then
|
||||
local cwd = system.absolute_path(".")
|
||||
return cwd .. PATHSEP .. common.normalize_path(filename)
|
||||
return common.basepath(cwd) .. common.normalize_path(filename)
|
||||
else
|
||||
return core.project_dir .. PATHSEP .. filename
|
||||
return common.basepath(core.project_dir) .. filename
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function core.init()
|
||||
core.log_items = {}
|
||||
core.log_quiet("Lite XL version %s - mod-version %s", VERSION, MOD_VERSION_STRING)
|
||||
|
||||
command = require "core.command"
|
||||
keymap = require "core.keymap"
|
||||
dirwatch = require "core.dirwatch"
|
||||
|
@ -716,7 +713,7 @@ function core.init()
|
|||
local file_abs = core.project_absolute_path(arg_filename)
|
||||
if file_abs then
|
||||
table.insert(files, file_abs)
|
||||
project_dir = file_abs:match("^(.+)[/\\].+$")
|
||||
project_dir = file_abs:match("^(.+)[:/\\].+$")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -724,6 +721,7 @@ function core.init()
|
|||
|
||||
core.frame_start = 0
|
||||
core.clip_rect_stack = {{ 0,0,0,0 }}
|
||||
core.log_items = {}
|
||||
core.docs = {}
|
||||
core.cursor_clipboard = {}
|
||||
core.cursor_clipboard_whole_line = {}
|
||||
|
@ -790,7 +788,7 @@ function core.init()
|
|||
local plugins_success, plugins_refuse_list = core.load_plugins()
|
||||
|
||||
do
|
||||
local pdir, pname = project_dir_abs:match("(.*)[/\\\\](.*)")
|
||||
local pdir, pname = project_dir_abs:match("(.*)[:/\\\\](.*)")
|
||||
core.log("Opening project %q from directory %s", pname, pdir)
|
||||
end
|
||||
|
||||
|
@ -825,19 +823,15 @@ function core.init()
|
|||
local msg = {}
|
||||
for _, entry in pairs(plugins_refuse_list) do
|
||||
if #entry.plugins > 0 then
|
||||
local msg_list = {}
|
||||
for _, p in pairs(entry.plugins) do
|
||||
table.insert(msg_list, string.format("%s[%s]", p.file, p.version_string))
|
||||
end
|
||||
msg[#msg + 1] = string.format("Plugins from directory \"%s\":\n%s", common.home_encode(entry.dir), table.concat(msg_list, "\n"))
|
||||
msg[#msg + 1] = string.format("Plugins from directory \"%s\":\n%s", common.home_encode(entry.dir), table.concat(entry.plugins, "\n"))
|
||||
end
|
||||
end
|
||||
core.nag_view:show(
|
||||
"Refused Plugins",
|
||||
string.format(
|
||||
"Some plugins are not loaded due to version mismatch. Expected version %s.\n\n%s.\n\n" ..
|
||||
"Some plugins are not loaded due to version mismatch.\n\n%s.\n\n" ..
|
||||
"Please download a recent version from https://github.com/lite-xl/lite-xl-plugins.",
|
||||
MOD_VERSION_STRING, table.concat(msg, ".\n\n")),
|
||||
table.concat(msg, ".\n\n")),
|
||||
opt, function(item)
|
||||
if item.text == "Exit" then os.exit(1) end
|
||||
end)
|
||||
|
@ -884,7 +878,7 @@ function core.delete_temp_files(dir)
|
|||
dir = type(dir) == "string" and common.normalize_path(dir) or USERDIR
|
||||
for _, filename in ipairs(system.list_dir(dir) or {}) do
|
||||
if filename:find(temp_file_prefix, 1, true) == 1 then
|
||||
os.remove(dir .. PATHSEP .. filename)
|
||||
os.remove(common.basepath(dir) .. filename)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -892,7 +886,7 @@ end
|
|||
function core.temp_filename(ext, dir)
|
||||
dir = type(dir) == "string" and common.normalize_path(dir) or USERDIR
|
||||
temp_file_counter = temp_file_counter + 1
|
||||
return dir .. PATHSEP .. temp_file_prefix
|
||||
return common.basepath(dir) .. temp_file_prefix
|
||||
.. string.format("%06x", temp_file_counter) .. (ext or "")
|
||||
end
|
||||
|
||||
|
@ -926,8 +920,6 @@ function core.restart()
|
|||
end
|
||||
|
||||
|
||||
local mod_version_regex =
|
||||
regex.compile([[--.*mod-version:(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:$|\s)]])
|
||||
local function get_plugin_details(filename)
|
||||
local info = system.get_file_info(filename)
|
||||
if info ~= nil and info.type == "dir" then
|
||||
|
@ -939,32 +931,17 @@ local function get_plugin_details(filename)
|
|||
if not f then return false end
|
||||
local priority = false
|
||||
local version_match = false
|
||||
local major, minor, patch
|
||||
|
||||
for line in f:lines() do
|
||||
if not version_match then
|
||||
local _major, _minor, _patch = mod_version_regex:match(line)
|
||||
if _major then
|
||||
_major = tonumber(_major) or 0
|
||||
_minor = tonumber(_minor) or 0
|
||||
_patch = tonumber(_patch) or 0
|
||||
major, minor, patch = _major, _minor, _patch
|
||||
|
||||
version_match = major == MOD_VERSION_MAJOR
|
||||
if version_match then
|
||||
version_match = minor <= MOD_VERSION_MINOR
|
||||
end
|
||||
if version_match then
|
||||
version_match = patch <= MOD_VERSION_PATCH
|
||||
end
|
||||
local mod_version = line:match('%-%-.*%f[%a]mod%-version%s*:%s*(%d+)')
|
||||
if mod_version then
|
||||
version_match = (mod_version == MOD_VERSION)
|
||||
end
|
||||
end
|
||||
|
||||
if not priority then
|
||||
priority = line:match('%-%-.*%f[%a]priority%s*:%s*(%d+)')
|
||||
if priority then priority = tonumber(priority) end
|
||||
end
|
||||
|
||||
if version_match then
|
||||
break
|
||||
end
|
||||
|
@ -972,7 +949,6 @@ local function get_plugin_details(filename)
|
|||
f:close()
|
||||
return true, {
|
||||
version_match = version_match,
|
||||
version = major and {major, minor, patch} or {},
|
||||
priority = priority or 100
|
||||
}
|
||||
end
|
||||
|
@ -986,7 +962,7 @@ function core.load_plugins()
|
|||
}
|
||||
local files, ordered = {}, {}
|
||||
for _, root_dir in ipairs {DATADIR, USERDIR} do
|
||||
local plugin_dir = root_dir .. PATHSEP .. "plugins"
|
||||
local plugin_dir = common.basepath(root_dir) .. "plugins"
|
||||
for _, filename in ipairs(system.list_dir(plugin_dir) or {}) do
|
||||
if not files[filename] then
|
||||
table.insert(
|
||||
|
@ -1001,15 +977,13 @@ function core.load_plugins()
|
|||
for _, plugin in ipairs(ordered) do
|
||||
local dir = files[plugin.file]
|
||||
local name = plugin.file:match("(.-)%.lua$") or plugin.file
|
||||
local is_lua_file, details = get_plugin_details(dir .. PATHSEP .. plugin.file)
|
||||
local is_lua_file, details = get_plugin_details(common.basepath(dir) .. plugin.file)
|
||||
|
||||
plugin.valid = is_lua_file
|
||||
plugin.name = name
|
||||
plugin.dir = dir
|
||||
plugin.priority = details and details.priority or 100
|
||||
plugin.version_match = details and details.version_match or false
|
||||
plugin.version = details and details.version or {}
|
||||
plugin.version_string = #plugin.version > 0 and table.concat(plugin.version, ".") or "unknown"
|
||||
end
|
||||
|
||||
-- sort by priority or name for plugins that have same priority
|
||||
|
@ -1025,35 +999,27 @@ function core.load_plugins()
|
|||
if plugin.valid then
|
||||
if not config.skip_plugins_version and not plugin.version_match then
|
||||
core.log_quiet(
|
||||
"Version mismatch for plugin %q[%s] from %s",
|
||||
"Version mismatch for plugin %q from %s",
|
||||
plugin.name,
|
||||
plugin.version_string,
|
||||
plugin.dir
|
||||
)
|
||||
local rlist = plugin.dir:find(USERDIR, 1, true) == 1
|
||||
and 'userdir' or 'datadir'
|
||||
local list = refused_list[rlist].plugins
|
||||
table.insert(list, plugin)
|
||||
table.insert(list, plugin.file)
|
||||
elseif config.plugins[plugin.name] ~= false then
|
||||
local start = system.get_time()
|
||||
local ok, loaded_plugin = core.try(require, "plugins." .. plugin.name)
|
||||
local ok = core.try(require, "plugins." .. plugin.name)
|
||||
if ok then
|
||||
local plugin_version = ""
|
||||
if plugin.version_string ~= MOD_VERSION_STRING then
|
||||
plugin_version = "["..plugin.version_string.."]"
|
||||
end
|
||||
core.log_quiet(
|
||||
"Loaded plugin %q%s from %s in %.1fms",
|
||||
"Loaded plugin %q from %s in %.1fms",
|
||||
plugin.name,
|
||||
plugin_version,
|
||||
plugin.dir,
|
||||
(system.get_time() - start) * 1000
|
||||
)
|
||||
end
|
||||
if not ok then
|
||||
no_errors = false
|
||||
elseif config.plugins[plugin.name].onload then
|
||||
core.try(config.plugins[plugin.name].onload, loaded_plugin)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1107,7 +1073,6 @@ function core.set_active_view(view)
|
|||
-- Reset the IME even if the focus didn't change
|
||||
ime.stop()
|
||||
if view ~= core.active_view then
|
||||
system.text_input(view:supports_text_input())
|
||||
if core.active_view and core.active_view.force_focus then
|
||||
core.next_active_view = view
|
||||
return
|
||||
|
@ -1296,12 +1261,6 @@ function core.on_event(type, ...)
|
|||
if not core.root_view:on_mouse_wheel(...) then
|
||||
did_keymap = keymap.on_mouse_wheel(...)
|
||||
end
|
||||
elseif type == "touchpressed" then
|
||||
core.root_view:on_touch_pressed(...)
|
||||
elseif type == "touchreleased" then
|
||||
core.root_view:on_touch_released(...)
|
||||
elseif type == "touchmoved" then
|
||||
core.root_view:on_touch_moved(...)
|
||||
elseif type == "resized" then
|
||||
core.window_mode = system.get_window_mode()
|
||||
elseif type == "minimized" or type == "maximized" or type == "restored" then
|
||||
|
@ -1351,11 +1310,6 @@ function core.step()
|
|||
did_keymap = false
|
||||
elseif type == "mousemoved" then
|
||||
core.try(core.on_event, type, a, b, c, d)
|
||||
elseif type == "enteringforeground" then
|
||||
-- to break our frame refresh in two if we get entering/entered at the same time.
|
||||
-- required to avoid flashing and refresh issues on mobile
|
||||
core.redraw = true
|
||||
break
|
||||
else
|
||||
local _, res = core.try(core.on_event, type, a, b, c, d)
|
||||
did_keymap = res or did_keymap
|
||||
|
@ -1412,10 +1366,11 @@ local run_threads = coroutine.wrap(function()
|
|||
else
|
||||
core.threads[k] = nil
|
||||
end
|
||||
else
|
||||
wait = wait or (1/30)
|
||||
elseif wait then
|
||||
thread.wake = system.get_time() + wait
|
||||
minimal_time_to_wake = math.min(minimal_time_to_wake, wait)
|
||||
else
|
||||
minimal_time_to_wake = 0
|
||||
end
|
||||
else
|
||||
minimal_time_to_wake = math.min(minimal_time_to_wake, thread.wake - system.get_time())
|
||||
|
@ -1496,7 +1451,7 @@ end
|
|||
|
||||
function core.on_error(err)
|
||||
-- write error to file
|
||||
local fp = io.open(USERDIR .. PATHSEP .. "error.txt", "wb")
|
||||
local fp = io.open(common.basepath(USERDIR) .. "error.txt", "wb")
|
||||
fp:write("Error: " .. tostring(err) .. "\n")
|
||||
fp:write(debug.traceback("", 4) .. "\n")
|
||||
fp:close()
|
||||
|
@ -1509,15 +1464,4 @@ function core.on_error(err)
|
|||
end
|
||||
|
||||
|
||||
local alerted_deprecations = {}
|
||||
---Show deprecation notice once per `kind`.
|
||||
---
|
||||
---@param kind string
|
||||
function core.deprecation_log(kind)
|
||||
if alerted_deprecations[kind] then return end
|
||||
alerted_deprecations[kind] = true
|
||||
core.warn("Used deprecated functionality [%s]. Check if your plugins are up to date.", kind)
|
||||
end
|
||||
|
||||
|
||||
return core
|
||||
|
|
|
@ -36,8 +36,6 @@ local function keymap_macos(keymap)
|
|||
["wheel"] = "root:scroll",
|
||||
["hwheel"] = "root:horizontal-scroll",
|
||||
["shift+hwheel"] = "root:horizontal-scroll",
|
||||
["wheelup"] = "root:scroll-hovered-tabs-backward",
|
||||
["wheeldown"] = "root:scroll-hovered-tabs-forward",
|
||||
|
||||
["cmd+f"] = "find-replace:find",
|
||||
["cmd+r"] = "find-replace:replace",
|
||||
|
|
|
@ -24,9 +24,11 @@ keymap.map = {}
|
|||
keymap.reverse_map = {}
|
||||
|
||||
local macos = PLATFORM == "Mac OS X"
|
||||
local os4 = PLATFORM == "AmigaOS 4"
|
||||
local mos = PLATFORM == "MORPHOS"
|
||||
|
||||
-- Thanks to mathewmariani, taken from his lite-macos github repository.
|
||||
local modkeys_os = require("core.modkeys-" .. (macos and "macos" or "generic"))
|
||||
local modkeys_os = require("core.modkeys-" .. (macos and "macos" or os4 and "os4" or mos and "mos" or "generic"))
|
||||
|
||||
---@type table<keymap.modkey, keymap.modkey>
|
||||
local modkey_map = modkeys_os.map
|
||||
|
@ -323,8 +325,6 @@ keymap.add_direct {
|
|||
["wheel"] = "root:scroll",
|
||||
["hwheel"] = "root:horizontal-scroll",
|
||||
["shift+wheel"] = "root:horizontal-scroll",
|
||||
["wheelup"] = "root:scroll-hovered-tabs-backward",
|
||||
["wheeldown"] = "root:scroll-hovered-tabs-forward",
|
||||
|
||||
["ctrl+f"] = "find-replace:find",
|
||||
["ctrl+r"] = "find-replace:replace",
|
||||
|
@ -341,7 +341,6 @@ keymap.add_direct {
|
|||
["ctrl+x"] = "doc:cut",
|
||||
["ctrl+c"] = "doc:copy",
|
||||
["ctrl+v"] = "doc:paste",
|
||||
["insert"] = "doc:toggle-overwrite",
|
||||
["ctrl+insert"] = "doc:copy",
|
||||
["shift+insert"] = "doc:paste",
|
||||
["escape"] = { "command:escape", "doc:select-none", "dialog:select-no" },
|
||||
|
@ -391,7 +390,7 @@ keymap.add_direct {
|
|||
["shift+1lclick"] = "doc:select-to-cursor",
|
||||
["ctrl+1lclick"] = "doc:split-cursor",
|
||||
["1lclick"] = "doc:set-cursor",
|
||||
["2lclick"] = { "doc:set-cursor-word", "emptyview:new-doc", "tabbar:new-doc" },
|
||||
["2lclick"] = "doc:set-cursor-word",
|
||||
["3lclick"] = "doc:set-cursor-line",
|
||||
["shift+left"] = "doc:select-to-previous-char",
|
||||
["shift+right"] = "doc:select-to-next-char",
|
||||
|
|
|
@ -7,12 +7,8 @@ modkeys.map = {
|
|||
["right shift"] = "shift",
|
||||
["left alt"] = "alt",
|
||||
["right alt"] = "altgr",
|
||||
["left gui"] = "super",
|
||||
["left windows"] = "super",
|
||||
["right gui"] = "super",
|
||||
["right windows"] = "super"
|
||||
}
|
||||
|
||||
modkeys.keys = { "ctrl", "shift", "alt", "altgr", "super" }
|
||||
modkeys.keys = { "ctrl", "shift", "alt", "altgr" }
|
||||
|
||||
return modkeys
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
local modkeys = {}
|
||||
|
||||
modkeys.map = {
|
||||
["left amiga"] = "cmd",
|
||||
["right amiga"] = "cmd",
|
||||
["control"] = "ctrl",
|
||||
["left shift"] = "shift",
|
||||
["right shift"] = "shift",
|
||||
["left alt"] = "alt",
|
||||
["right alt"] = "altgr",
|
||||
}
|
||||
|
||||
modkeys.keys = { "cmd", "ctrl", "alt", "altgr", "shift" }
|
||||
|
||||
return modkeys
|
|
@ -0,0 +1,15 @@
|
|||
local modkeys = {}
|
||||
|
||||
modkeys.map = {
|
||||
["left amiga"] = "cmd",
|
||||
["right amiga"] = "cmd",
|
||||
["control"] = "ctrl",
|
||||
["left shift"] = "shift",
|
||||
["right shift"] = "shift",
|
||||
["left alt"] = "alt",
|
||||
["right alt"] = "altgr",
|
||||
}
|
||||
|
||||
modkeys.keys = { "cmd", "ctrl", "alt", "altgr", "shift" }
|
||||
|
||||
return modkeys
|
|
@ -24,7 +24,6 @@ function NagView:new()
|
|||
self.scrollable = true
|
||||
self.target_height = 0
|
||||
self.on_mouse_pressed_root = nil
|
||||
self.dim_alpha = 0
|
||||
end
|
||||
|
||||
function NagView:get_title()
|
||||
|
@ -69,9 +68,7 @@ function NagView:dim_window_content()
|
|||
oy = oy + self.show_height
|
||||
local w, h = core.root_view.size.x, core.root_view.size.y - oy
|
||||
core.root_view:defer_draw(function()
|
||||
local dim_color = { table.unpack(style.nagbar_dim) }
|
||||
dim_color[4] = style.nagbar_dim[4] * self.dim_alpha
|
||||
renderer.draw_rect(ox, oy, w, h, dim_color)
|
||||
renderer.draw_rect(ox, oy, w, h, style.nagbar_dim)
|
||||
end)
|
||||
end
|
||||
|
||||
|
@ -175,13 +172,10 @@ function NagView:update()
|
|||
NagView.super.update(self)
|
||||
|
||||
if self.visible and core.active_view == self and self.title then
|
||||
local target_height = self:get_target_height()
|
||||
self:move_towards(self, "show_height", target_height, nil, "nagbar")
|
||||
self:move_towards(self, "show_height", self:get_target_height(), nil, "nagbar")
|
||||
self:move_towards(self, "underline_progress", 1, nil, "nagbar")
|
||||
self:move_towards(self, "dim_alpha", self.show_height / target_height, nil, "nagbar")
|
||||
else
|
||||
self:move_towards(self, "show_height", 0, nil, "nagbar")
|
||||
self:move_towards(self, "dim_alpha", 0, nil, "nagbar")
|
||||
if self.show_height <= 0 then
|
||||
self.title = nil
|
||||
self.message = nil
|
||||
|
|
|
@ -18,6 +18,7 @@ function Node:new(type)
|
|||
if self.type == "leaf" then
|
||||
self:add_view(EmptyView())
|
||||
end
|
||||
self.hovered = {x = -1, y = -1 }
|
||||
self.hovered_close = 0
|
||||
self.tab_shift = 0
|
||||
self.tab_offset = 1
|
||||
|
@ -32,10 +33,9 @@ function Node:propagate(fn, ...)
|
|||
end
|
||||
|
||||
|
||||
---@deprecated
|
||||
function Node:on_mouse_moved(x, y, ...)
|
||||
core.deprecation_log("Node:on_mouse_moved")
|
||||
if self.type == "leaf" then
|
||||
self.hovered.x, self.hovered.y = x, y
|
||||
self.active_view:on_mouse_moved(x, y, ...)
|
||||
else
|
||||
self:propagate("on_mouse_moved", x, y, ...)
|
||||
|
@ -43,9 +43,7 @@ function Node:on_mouse_moved(x, y, ...)
|
|||
end
|
||||
|
||||
|
||||
---@deprecated
|
||||
function Node:on_mouse_released(...)
|
||||
core.deprecation_log("Node:on_mouse_released")
|
||||
if self.type == "leaf" then
|
||||
self.active_view:on_mouse_released(...)
|
||||
else
|
||||
|
@ -54,9 +52,7 @@ function Node:on_mouse_released(...)
|
|||
end
|
||||
|
||||
|
||||
---@deprecated
|
||||
function Node:on_mouse_left()
|
||||
core.deprecation_log("Node:on_mouse_left")
|
||||
if self.type == "leaf" then
|
||||
self.active_view:on_mouse_left()
|
||||
else
|
||||
|
@ -65,17 +61,6 @@ function Node:on_mouse_left()
|
|||
end
|
||||
|
||||
|
||||
---@deprecated
|
||||
function Node:on_touch_moved(...)
|
||||
core.deprecation_log("Node:on_touch_moved")
|
||||
if self.type == "leaf" then
|
||||
self.active_view:on_touch_moved(...)
|
||||
else
|
||||
self:propagate("on_touch_moved", ...)
|
||||
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
|
||||
|
@ -177,12 +162,8 @@ function Node:add_view(view, idx)
|
|||
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)
|
||||
if idx and idx > 1 then
|
||||
idx = idx - 1
|
||||
end
|
||||
end
|
||||
idx = common.clamp(idx or (#self.views + 1), 1, (#self.views + 1))
|
||||
table.insert(self.views, idx, view)
|
||||
table.insert(self.views, idx or (#self.views + 1), view)
|
||||
self:set_active_view(view)
|
||||
end
|
||||
|
||||
|
@ -320,7 +301,7 @@ function Node:tab_hovered_update(px, py)
|
|||
if px >= cx and px < cx + cw and py >= y and py < y + h and config.tab_close_button then
|
||||
self.hovered_close = tab_index
|
||||
end
|
||||
elseif #self.views > self:get_visible_tabs_number() then
|
||||
else
|
||||
self.hovered_scroll_button = self:get_scroll_button_index(px, py) or 0
|
||||
end
|
||||
end
|
||||
|
@ -338,17 +319,10 @@ function Node:get_child_overlapping_point(x, y)
|
|||
return child:get_child_overlapping_point(x, y)
|
||||
end
|
||||
|
||||
-- returns: total height, text padding, top margin
|
||||
local function get_tab_y_sizes()
|
||||
local height = style.font:get_height()
|
||||
local padding = style.padding.y
|
||||
local margin = style.margin.tab.top
|
||||
return height + (padding * 2) + margin, padding, margin
|
||||
end
|
||||
|
||||
function Node:get_scroll_button_rect(index)
|
||||
local w, pad = get_scroll_button_width()
|
||||
local h = get_tab_y_sizes()
|
||||
local h = style.font:get_height() + style.padding.y * 2
|
||||
local x = self.position.x + (index == 1 and self.size.x - w * 2 or self.size.x - w)
|
||||
return x, self.position.y, w, h, pad
|
||||
end
|
||||
|
@ -359,8 +333,8 @@ function Node:get_tab_rect(idx)
|
|||
local x0 = self.position.x
|
||||
local x1 = x0 + common.clamp(self.tab_width * (idx - 1) - self.tab_shift, 0, maxw)
|
||||
local x2 = x0 + common.clamp(self.tab_width * idx - self.tab_shift, 0, maxw)
|
||||
local h, pad_y, margin_y = get_tab_y_sizes()
|
||||
return x1, self.position.y, x2 - x1, h, margin_y
|
||||
local h = style.font:get_height() + style.padding.y * 2
|
||||
return x1, self.position.y, x2 - x1, h
|
||||
end
|
||||
|
||||
|
||||
|
@ -508,7 +482,7 @@ function Node:update()
|
|||
for _, view in ipairs(self.views) do
|
||||
view:update()
|
||||
end
|
||||
self:tab_hovered_update(core.root_view.mouse.x, core.root_view.mouse.y)
|
||||
self:tab_hovered_update(self.hovered.x, self.hovered.y)
|
||||
local tab_width = self:target_tab_width()
|
||||
self:move_towards("tab_shift", tab_width * (self.tab_offset - 1), nil, "tabs")
|
||||
self:move_towards("tab_width", tab_width, nil, "tabs")
|
||||
|
@ -551,7 +525,6 @@ function Node:draw_tab_borders(view, is_active, is_hovered, x, y, w, h, standalo
|
|||
if is_active then
|
||||
color = style.text
|
||||
renderer.draw_rect(x, y, w, h, style.background)
|
||||
renderer.draw_rect(x, y, w, ds, style.divider)
|
||||
renderer.draw_rect(x + w, y, ds, h, style.divider)
|
||||
renderer.draw_rect(x - ds, y, ds, h, style.divider)
|
||||
end
|
||||
|
@ -559,8 +532,7 @@ function Node:draw_tab_borders(view, is_active, is_hovered, x, y, w, h, standalo
|
|||
end
|
||||
|
||||
function Node:draw_tab(view, is_active, is_hovered, is_close_hovered, x, y, w, h, standalone)
|
||||
local _, padding_y, margin_y = get_tab_y_sizes()
|
||||
x, y, w, h = self:draw_tab_borders(view, is_active, is_hovered, x, y + margin_y, w, h - margin_y, standalone)
|
||||
x, y, w, h = self:draw_tab_borders(view, is_active, is_hovered, x, y, w, h, standalone)
|
||||
-- Close button
|
||||
local cx, cw, cpad = close_button_location(x, w)
|
||||
local show_close_button = ((is_active or is_hovered) and not standalone and config.tab_close_button)
|
||||
|
@ -636,13 +608,6 @@ function Node:is_empty()
|
|||
end
|
||||
|
||||
|
||||
function Node:is_in_tab_area(x, y)
|
||||
if not self:should_show_tabs() then return false end
|
||||
local _, ty, _, th = self:get_scroll_button_rect(1)
|
||||
return y >= ty and y < ty + th
|
||||
end
|
||||
|
||||
|
||||
function Node:close_all_docviews(keep_active)
|
||||
local node_active_view = self.active_view
|
||||
local lost_active_view = false
|
||||
|
@ -781,7 +746,7 @@ function Node:get_drag_overlay_tab_position(x, y, dragged_node, dragged_index)
|
|||
tab_index = self:get_visible_tabs_number() + (self.tab_offset - 1 or 0)
|
||||
end
|
||||
end
|
||||
local tab_x, tab_y, tab_w, tab_h, margin_y = self:get_tab_rect(tab_index)
|
||||
local tab_x, tab_y, tab_w, tab_h = self:get_tab_rect(tab_index)
|
||||
if x > tab_x + tab_w / 2 and tab_index <= #self.views then
|
||||
-- use next tab
|
||||
tab_x = tab_x + tab_w
|
||||
|
@ -792,7 +757,7 @@ function Node:get_drag_overlay_tab_position(x, y, dragged_node, dragged_index)
|
|||
tab_index = tab_index - 1
|
||||
tab_x = tab_x - tab_w
|
||||
end
|
||||
return tab_index, tab_x, tab_y + margin_y, tab_w, tab_h - margin_y
|
||||
return tab_index, tab_x, tab_y, tab_w, tab_h
|
||||
end
|
||||
|
||||
return Node
|
||||
|
|
|
@ -27,13 +27,6 @@ function Object:is(T)
|
|||
return getmetatable(self) == T
|
||||
end
|
||||
|
||||
---Check if the parameter is strictly of the object type.
|
||||
---@param T any
|
||||
---@return boolean
|
||||
function Object:is_class_of(T)
|
||||
return getmetatable(T) == self
|
||||
end
|
||||
|
||||
---Check if the object inherits from the given type.
|
||||
---@param T any
|
||||
---@return boolean
|
||||
|
@ -48,22 +41,6 @@ function Object:extends(T)
|
|||
return false
|
||||
end
|
||||
|
||||
---Check if the parameter inherits from the object.
|
||||
---@param T any
|
||||
---@return boolean
|
||||
function Object:is_extended_by(T)
|
||||
local mt = getmetatable(T)
|
||||
while mt do
|
||||
if mt == self then
|
||||
return true
|
||||
end
|
||||
local _mt = getmetatable(T)
|
||||
if mt == _mt then break end
|
||||
mt = _mt
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
---Metamethod to get a string representation of an object.
|
||||
---@return string
|
||||
function Object:__tostring()
|
||||
|
|
|
@ -24,9 +24,6 @@ function RootView:new()
|
|||
base_color = style.drag_overlay_tab,
|
||||
color = { table.unpack(style.drag_overlay_tab) } }
|
||||
self.drag_overlay_tab.to = { x = 0, y = 0, w = 0, h = 0 }
|
||||
self.grab = nil -- = {view = nil, button = nil}
|
||||
self.overlapping_view = nil
|
||||
self.touched_view = nil
|
||||
end
|
||||
|
||||
|
||||
|
@ -119,31 +116,6 @@ function RootView:close_all_docviews(keep_active)
|
|||
end
|
||||
|
||||
|
||||
---Obtain mouse grab.
|
||||
---
|
||||
---This means that mouse movements will be sent to the specified view, even when
|
||||
---those occur outside of it.
|
||||
---There can't be multiple mouse grabs, even for different buttons.
|
||||
---@see RootView:ungrab_mouse
|
||||
---@param button core.view.mousebutton
|
||||
---@param view core.view
|
||||
function RootView:grab_mouse(button, view)
|
||||
assert(self.grab == nil)
|
||||
self.grab = {view = view, button = button}
|
||||
end
|
||||
|
||||
|
||||
---Release mouse grab.
|
||||
---
|
||||
---The specified button *must* be the last button that grabbed the mouse.
|
||||
---@see RootView:grab_mouse
|
||||
---@param button core.view.mousebutton
|
||||
function RootView:ungrab_mouse(button)
|
||||
assert(self.grab and self.grab.button == button)
|
||||
self.grab = nil
|
||||
end
|
||||
|
||||
|
||||
---Function to intercept mouse pressed events on the active view.
|
||||
---Do nothing by default.
|
||||
---@param button core.view.mousebutton
|
||||
|
@ -160,10 +132,6 @@ end
|
|||
---@param clicks integer
|
||||
---@return boolean
|
||||
function RootView:on_mouse_pressed(button, x, y, clicks)
|
||||
-- If there is a grab, release it first
|
||||
if self.grab then
|
||||
self:on_mouse_released(self.grab.button, x, y)
|
||||
end
|
||||
local div = self.root_node:get_divider_overlapping_point(x, y)
|
||||
local node = self.root_node:get_child_overlapping_point(x, y)
|
||||
if div and (node and not node.active_view:scrollbar_overlaps_point(x, y)) then
|
||||
|
@ -188,7 +156,6 @@ function RootView:on_mouse_pressed(button, x, y, clicks)
|
|||
end
|
||||
elseif not self.dragged_node then -- avoid sending on_mouse_pressed events when dragging tabs
|
||||
core.set_active_view(node.active_view)
|
||||
self:grab_mouse(button, node.active_view)
|
||||
return self.on_view_mouse_pressed(button, x, y, clicks) or node.active_view:on_mouse_pressed(button, x, y, clicks)
|
||||
end
|
||||
end
|
||||
|
@ -221,21 +188,6 @@ end
|
|||
---@param x number
|
||||
---@param y number
|
||||
function RootView:on_mouse_released(button, x, y, ...)
|
||||
if self.grab then
|
||||
if self.grab.button == button then
|
||||
local grabbed_view = self.grab.view
|
||||
grabbed_view:on_mouse_released(button, x, y, ...)
|
||||
self:ungrab_mouse(button)
|
||||
|
||||
-- If the mouse was released over a different view, send it the mouse position
|
||||
local hovered_view = self.root_node:get_child_overlapping_point(x, y)
|
||||
if grabbed_view ~= hovered_view then
|
||||
self:on_mouse_moved(x, y, 0, 0)
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if self.dragged_divider then
|
||||
self.dragged_divider = nil
|
||||
end
|
||||
|
@ -276,6 +228,8 @@ function RootView:on_mouse_released(button, x, y, ...)
|
|||
end
|
||||
self.dragged_node = nil
|
||||
end
|
||||
else -- avoid sending on_mouse_released events when dragging tabs
|
||||
self.root_node:on_mouse_released(button, x, y, ...)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -296,14 +250,6 @@ end
|
|||
---@param dx number
|
||||
---@param dy number
|
||||
function RootView:on_mouse_moved(x, y, dx, dy)
|
||||
self.mouse.x, self.mouse.y = x, y
|
||||
|
||||
if self.grab then
|
||||
self.grab.view:on_mouse_moved(x, y, dx, dy)
|
||||
core.request_cursor(self.grab.view.cursor)
|
||||
return
|
||||
end
|
||||
|
||||
if core.active_view == core.nag_view then
|
||||
core.request_cursor("arrow")
|
||||
core.active_view:on_mouse_moved(x, y, dx, dy)
|
||||
|
@ -323,6 +269,8 @@ function RootView:on_mouse_moved(x, y, dx, dy)
|
|||
return
|
||||
end
|
||||
|
||||
self.mouse.x, self.mouse.y = x, y
|
||||
|
||||
local dn = self.dragged_node
|
||||
if dn and not dn.dragging then
|
||||
-- start dragging only after enough movement
|
||||
|
@ -335,33 +283,32 @@ function RootView:on_mouse_moved(x, y, dx, dy)
|
|||
-- avoid sending on_mouse_moved events when dragging tabs
|
||||
if dn then return end
|
||||
|
||||
local last_overlapping_view = self.overlapping_view
|
||||
local overlapping_node = self.root_node:get_child_overlapping_point(x, y)
|
||||
self.overlapping_view = overlapping_node and overlapping_node.active_view
|
||||
self.root_node:on_mouse_moved(x, y, dx, dy)
|
||||
|
||||
if last_overlapping_view and last_overlapping_view ~= self.overlapping_view then
|
||||
last_overlapping_view:on_mouse_left()
|
||||
local last_overlapping_node = self.overlapping_node
|
||||
self.overlapping_node = self.root_node:get_child_overlapping_point(x, y)
|
||||
|
||||
if last_overlapping_node and last_overlapping_node ~= self.overlapping_node then
|
||||
last_overlapping_node:on_mouse_left()
|
||||
end
|
||||
|
||||
if not self.overlapping_view then return end
|
||||
|
||||
self.overlapping_view:on_mouse_moved(x, y, dx, dy)
|
||||
core.request_cursor(self.overlapping_view.cursor)
|
||||
|
||||
if not overlapping_node then return end
|
||||
|
||||
local div = self.root_node:get_divider_overlapping_point(x, y)
|
||||
if overlapping_node:get_scroll_button_index(x, y) or overlapping_node:is_in_tab_area(x, y) then
|
||||
local tab_index = self.overlapping_node and self.overlapping_node:get_tab_overlapping_point(x, y)
|
||||
if self.overlapping_node and self.overlapping_node:get_scroll_button_index(x, y) then
|
||||
core.request_cursor("arrow")
|
||||
elseif div and not self.overlapping_view:scrollbar_overlaps_point(x, y) then
|
||||
elseif div and (self.overlapping_node and not self.overlapping_node.active_view:scrollbar_overlaps_point(x, y)) then
|
||||
core.request_cursor(div.type == "hsplit" and "sizeh" or "sizev")
|
||||
elseif tab_index then
|
||||
core.request_cursor("arrow")
|
||||
elseif self.overlapping_node then
|
||||
core.request_cursor(self.overlapping_node.active_view.cursor)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function RootView:on_mouse_left()
|
||||
if self.overlapping_view then
|
||||
self.overlapping_view:on_mouse_left()
|
||||
if self.overlapping_node then
|
||||
self.overlapping_node:on_mouse_left()
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -387,50 +334,6 @@ function RootView:on_text_input(...)
|
|||
core.active_view:on_text_input(...)
|
||||
end
|
||||
|
||||
function RootView:on_touch_pressed(x, y, ...)
|
||||
local touched_node = self.root_node:get_child_overlapping_point(x, y)
|
||||
self.touched_view = touched_node and touched_node.active_view
|
||||
end
|
||||
|
||||
function RootView:on_touch_released(x, y, ...)
|
||||
self.touched_view = nil
|
||||
end
|
||||
|
||||
function RootView:on_touch_moved(x, y, dx, dy, ...)
|
||||
if not self.touched_view then return end
|
||||
if core.active_view == core.nag_view then
|
||||
core.active_view:on_touch_moved(x, y, dx, dy, ...)
|
||||
return
|
||||
end
|
||||
|
||||
if self.dragged_divider then
|
||||
local node = self.dragged_divider
|
||||
if node.type == "hsplit" then
|
||||
x = common.clamp(x - node.position.x, 0, self.root_node.size.x * 0.95)
|
||||
resize_child_node(node, "x", x, dx)
|
||||
elseif node.type == "vsplit" then
|
||||
y = common.clamp(y - node.position.y, 0, self.root_node.size.y * 0.95)
|
||||
resize_child_node(node, "y", y, dy)
|
||||
end
|
||||
node.divider = common.clamp(node.divider, 0.01, 0.99)
|
||||
return
|
||||
end
|
||||
|
||||
local dn = self.dragged_node
|
||||
if dn and not dn.dragging then
|
||||
-- start dragging only after enough movement
|
||||
dn.dragging = common.distance(x, y, dn.drag_start_x, dn.drag_start_y) > style.tab_width * .05
|
||||
if dn.dragging then
|
||||
core.request_cursor("hand")
|
||||
end
|
||||
end
|
||||
|
||||
-- avoid sending on_touch_moved events when dragging tabs
|
||||
if dn then return end
|
||||
|
||||
self.touched_view:on_touch_moved(x, y, dx, dy, ...)
|
||||
end
|
||||
|
||||
function RootView:on_ime_text_editing(...)
|
||||
core.active_view:on_ime_text_editing(...)
|
||||
end
|
||||
|
|
|
@ -58,9 +58,9 @@ function Scrollbar:new(options)
|
|||
---@type "expanded" | "contracted" | false @Force the scrollbar status
|
||||
self.force_status = options.force_status
|
||||
self:set_forced_status(options.force_status)
|
||||
---@type number? @Override the default value specified by `style.scrollbar_size`
|
||||
self.contracted_size = options.contracted_size
|
||||
---@type number? @Override the default value specified by `style.expanded_scrollbar_size`
|
||||
self.contracted_size = options.contracted_size
|
||||
---@type number? @Override the default value specified by `style.scrollbar_size`
|
||||
self.expanded_size = options.expanded_size
|
||||
end
|
||||
|
||||
|
@ -121,7 +121,7 @@ function Scrollbar:_get_thumb_rect_normal()
|
|||
across_size = across_size + (expanded_scrollbar_size - scrollbar_size) * self.expand_percent
|
||||
return
|
||||
nr.across + nr.across_size - across_size,
|
||||
nr.along + self.percent * (nr.along_size - along_size),
|
||||
nr.along + self.percent * nr.scrollable * (nr.along_size - along_size) / (sz - nr.along_size),
|
||||
across_size,
|
||||
along_size
|
||||
end
|
||||
|
@ -238,8 +238,7 @@ end
|
|||
function Scrollbar:_on_mouse_moved_normal(x, y, dx, dy)
|
||||
if self.dragging then
|
||||
local nr = self.normal_rect
|
||||
local _, _, _, along_size = self:_get_thumb_rect_normal()
|
||||
return common.clamp((y - nr.along + self.drag_start_offset) / (nr.along_size - along_size), 0, 1)
|
||||
return common.clamp((y - nr.along + self.drag_start_offset) / nr.along_size, 0, 1)
|
||||
end
|
||||
return self:_update_hover_status_normal(x, y)
|
||||
end
|
||||
|
@ -282,7 +281,7 @@ function Scrollbar:set_size(x, y, w, h, scrollable)
|
|||
end
|
||||
|
||||
---Updates the scrollbar location
|
||||
---@param percent number @number between 0 and 1 where 0 means thumb at the top and 1 at the bottom
|
||||
---@param percent number @number between 0 and 1 representing the position of the middle part of the thumb
|
||||
function Scrollbar:set_percent(percent)
|
||||
self.percent = percent
|
||||
end
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
-- this file is used by lite-xl to setup the Lua environment when starting
|
||||
VERSION = "@PROJECT_VERSION@"
|
||||
MOD_VERSION_MAJOR = 3
|
||||
MOD_VERSION_MINOR = 0
|
||||
MOD_VERSION_PATCH = 0
|
||||
MOD_VERSION_STRING = string.format("%d.%d.%d", MOD_VERSION_MAJOR, MOD_VERSION_MINOR, MOD_VERSION_PATCH)
|
||||
VERSION = "2.1.4r1"
|
||||
MOD_VERSION = "3"
|
||||
|
||||
SCALE = tonumber(os.getenv("LITE_SCALE") or os.getenv("GDK_SCALE") or os.getenv("QT_SCALE_FACTOR")) or 1
|
||||
PATHSEP = package.config:sub(1, 1)
|
||||
|
@ -25,7 +22,7 @@ package.path = DATADIR .. '/?/init.lua;' .. package.path
|
|||
package.path = USERDIR .. '/?.lua;' .. package.path
|
||||
package.path = USERDIR .. '/?/init.lua;' .. package.path
|
||||
|
||||
local suffix = PLATFORM == "Windows" and 'dll' or 'so'
|
||||
local suffix = PLATFORM == "Mac OS X" and 'lib' or (PLATFORM == "Windows" and 'dll' or 'so')
|
||||
package.cpath =
|
||||
USERDIR .. '/?.' .. ARCH .. "." .. suffix .. ";" ..
|
||||
USERDIR .. '/?/init.' .. ARCH .. "." .. suffix .. ";" ..
|
||||
|
|
|
@ -232,42 +232,15 @@ function StatusView:register_docview_items()
|
|||
return {
|
||||
style.text, line, ":",
|
||||
col > config.line_limit and style.accent or style.text, col,
|
||||
style.text
|
||||
style.text,
|
||||
self.separator,
|
||||
string.format("%.f%%", line / #dv.doc.lines * 100)
|
||||
}
|
||||
end,
|
||||
command = "doc:go-to-line",
|
||||
tooltip = "line : column"
|
||||
})
|
||||
|
||||
self:add_item({
|
||||
predicate = predicate_docview,
|
||||
name = "doc:position-percent",
|
||||
alignment = StatusView.Item.LEFT,
|
||||
get_item = function()
|
||||
local dv = core.active_view
|
||||
local line = dv.doc:get_selection()
|
||||
return {
|
||||
string.format("%.f%%", line / #dv.doc.lines * 100)
|
||||
}
|
||||
end,
|
||||
tooltip = "caret position"
|
||||
})
|
||||
|
||||
self:add_item({
|
||||
predicate = predicate_docview,
|
||||
name = "doc:selections",
|
||||
alignment = StatusView.Item.LEFT,
|
||||
get_item = function()
|
||||
local dv = core.active_view
|
||||
local nsel = math.floor(#dv.doc.selections / 4)
|
||||
if nsel > 1 then
|
||||
return { style.text, nsel, " selections" }
|
||||
end
|
||||
|
||||
return {}
|
||||
end
|
||||
})
|
||||
|
||||
self:add_item({
|
||||
predicate = predicate_docview,
|
||||
name = "doc:indentation",
|
||||
|
@ -319,19 +292,6 @@ function StatusView:register_docview_items()
|
|||
end,
|
||||
command = "doc:toggle-line-ending"
|
||||
})
|
||||
|
||||
self:add_item {
|
||||
predicate = predicate_docview,
|
||||
name = "doc:overwrite-mode",
|
||||
alignment = StatusView.Item.RIGHT,
|
||||
get_item = function()
|
||||
return {
|
||||
style.text, core.active_view.doc.overwrite and "OVR" or "INS"
|
||||
}
|
||||
end,
|
||||
command = "doc:toggle-overwrite",
|
||||
separator = StatusView.separator2
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
|
@ -1014,12 +974,6 @@ function StatusView:on_mouse_pressed(button, x, y, clicks)
|
|||
end
|
||||
|
||||
|
||||
function StatusView:on_mouse_left()
|
||||
StatusView.super.on_mouse_left(self)
|
||||
self.hovered_item = {}
|
||||
end
|
||||
|
||||
|
||||
function StatusView:on_mouse_moved(x, y, dx, dy)
|
||||
if not self.visible then return end
|
||||
StatusView.super.on_mouse_moved(self, x, y, dx, dy)
|
||||
|
|
|
@ -1,23 +1,13 @@
|
|||
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.expanded_scrollbar_size = common.round(12 * SCALE)
|
||||
style.caret_width = common.round(2 * SCALE)
|
||||
style.tab_width = common.round(170 * SCALE)
|
||||
|
||||
style.padding = {
|
||||
x = common.round(14 * SCALE),
|
||||
y = common.round(7 * SCALE),
|
||||
}
|
||||
|
||||
style.margin = {
|
||||
tab = {
|
||||
top = common.round(-style.divider_size * SCALE)
|
||||
}
|
||||
}
|
||||
|
||||
-- The function renderer.font.load can accept an option table as a second optional argument.
|
||||
-- It shoud be like the following:
|
||||
--
|
||||
|
|
|
@ -3,7 +3,7 @@ local common = require "core.common"
|
|||
local syntax = {}
|
||||
syntax.items = {}
|
||||
|
||||
syntax.plain_text_syntax = { name = "Plain Text", patterns = {}, symbols = {} }
|
||||
local plain_text_syntax = { name = "Plain Text", patterns = {}, symbols = {} }
|
||||
|
||||
|
||||
function syntax.add(t)
|
||||
|
@ -46,7 +46,7 @@ end
|
|||
function syntax.get(filename, header)
|
||||
return (filename and find(filename, "files"))
|
||||
or (header and find(header, "headers"))
|
||||
or syntax.plain_text_syntax
|
||||
or plain_text_syntax
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -112,12 +112,6 @@ function TitleView:on_mouse_pressed(button, x, y, clicks)
|
|||
end
|
||||
|
||||
|
||||
function TitleView:on_mouse_left()
|
||||
TitleView.super.on_mouse_left(self)
|
||||
self.hovered_item = nil
|
||||
end
|
||||
|
||||
|
||||
function TitleView:on_mouse_moved(px, py, ...)
|
||||
if self.size.y == 0 then return end
|
||||
TitleView.super.on_mouse_moved(self, px, py, ...)
|
||||
|
|
|
@ -28,8 +28,11 @@ local function push_tokens(t, syn, pattern, full_text, find_results)
|
|||
-- Each position spans characters from i_n to ((i_n+1) - 1), to form
|
||||
-- consecutive spans of text.
|
||||
--
|
||||
-- Insert the start index at i_1 to make iterating easier
|
||||
table.insert(find_results, 3, find_results[1])
|
||||
-- If i_1 is not equal to start, start is automatically inserted at
|
||||
-- that index.
|
||||
if find_results[3] ~= find_results[1] then
|
||||
table.insert(find_results, 3, find_results[1])
|
||||
end
|
||||
-- Copy the ending index to the end of the table, so that an ending index
|
||||
-- always follows a starting index after position 3 in the table.
|
||||
table.insert(find_results, find_results[2] + 1)
|
||||
|
@ -39,10 +42,8 @@ local function push_tokens(t, syn, pattern, full_text, find_results)
|
|||
local fin = find_results[i + 1] - 1
|
||||
local type = pattern.type[i - 2]
|
||||
-- ↑ (i - 2) to convert from [3; n] to [1; n]
|
||||
if fin >= start then
|
||||
local text = full_text:usub(start, fin)
|
||||
push_token(t, syn.symbols[text] or type, text)
|
||||
end
|
||||
local text = full_text:usub(start, fin)
|
||||
push_token(t, syn.symbols[text] or type, text)
|
||||
end
|
||||
else
|
||||
local start, fin = find_results[1], find_results[2]
|
||||
|
@ -122,8 +123,10 @@ local function report_bad_pattern(log_fn, syntax, pattern_idx, msg, ...)
|
|||
end
|
||||
if bad_patterns[syntax][pattern_idx] then return end
|
||||
bad_patterns[syntax][pattern_idx] = true
|
||||
log_fn("Malformed pattern #%d in %s language plugin. " .. msg,
|
||||
pattern_idx, syntax.name or "unnamed", ...)
|
||||
log_fn("Malformed pattern #%d <%s> in %s language plugin.\n" .. msg,
|
||||
pattern_idx,
|
||||
syntax.patterns[pattern_idx].pattern or syntax.patterns[pattern_idx].regex,
|
||||
syntax.name or "unnamed", ...)
|
||||
end
|
||||
|
||||
---@param incoming_syntax table
|
||||
|
@ -133,12 +136,12 @@ function tokenizer.tokenize(incoming_syntax, text, state, resume)
|
|||
local res
|
||||
local i = 1
|
||||
|
||||
state = state or string.char(0)
|
||||
|
||||
if #incoming_syntax.patterns == 0 then
|
||||
return { "normal", text }, state
|
||||
return { "normal", text }
|
||||
end
|
||||
|
||||
state = state or string.char(0)
|
||||
|
||||
if resume then
|
||||
res = resume.res
|
||||
-- Remove "incomplete" tokens
|
||||
|
@ -241,7 +244,6 @@ function tokenizer.tokenize(incoming_syntax, text, state, resume)
|
|||
res[1] = char_pos_1
|
||||
res[2] = char_pos_2
|
||||
end
|
||||
if not res[1] then return end
|
||||
if res[1] and target[3] then
|
||||
-- Check to see if the escaped character is there,
|
||||
-- and if it is not itself escaped.
|
||||
|
@ -253,19 +255,19 @@ function tokenizer.tokenize(incoming_syntax, text, state, resume)
|
|||
if count % 2 == 0 then
|
||||
-- The match is not escaped, so confirm it
|
||||
break
|
||||
else
|
||||
-- The match is escaped, so avoid it
|
||||
res[1] = false
|
||||
elseif not close then
|
||||
-- The *open* match is escaped, so avoid it
|
||||
return
|
||||
end
|
||||
end
|
||||
until at_start or not close or not target[3]
|
||||
until not res[1] or not close or not target[3]
|
||||
return table.unpack(res)
|
||||
end
|
||||
|
||||
local text_len = text:ulen()
|
||||
local start_time = system.get_time()
|
||||
local starting_i = i
|
||||
while i <= text_len do
|
||||
while text_len ~= nil and i <= text_len do
|
||||
-- Every 200 chars, check if we're out of time
|
||||
if i - starting_i > 200 then
|
||||
starting_i = i
|
||||
|
@ -283,9 +285,6 @@ function tokenizer.tokenize(incoming_syntax, text, state, resume)
|
|||
if current_pattern_idx > 0 then
|
||||
local p = current_syntax.patterns[current_pattern_idx]
|
||||
local s, e = find_text(text, p, i, false, true)
|
||||
-- Use the first token type specified in the type table for the "middle"
|
||||
-- part of the subsyntax.
|
||||
local token_type = type(p.type) == "table" and p.type[1] or p.type
|
||||
|
||||
local cont = true
|
||||
-- If we're in subsyntax mode, always check to see if we end our syntax
|
||||
|
@ -298,7 +297,7 @@ function tokenizer.tokenize(incoming_syntax, text, state, resume)
|
|||
-- treat the bit after as a token to be normally parsed
|
||||
-- (as it's the syntax delimiter).
|
||||
if ss and (s == nil or ss < s) then
|
||||
push_token(res, token_type, text:usub(i, ss - 1))
|
||||
push_token(res, p.type, text:usub(i, ss - 1))
|
||||
i = ss
|
||||
cont = false
|
||||
end
|
||||
|
@ -307,11 +306,11 @@ function tokenizer.tokenize(incoming_syntax, text, state, resume)
|
|||
-- continue on as normal.
|
||||
if cont then
|
||||
if s then
|
||||
push_token(res, token_type, text:usub(i, e))
|
||||
push_token(res, p.type, text:usub(i, e))
|
||||
set_subsyntax_pattern_idx(0)
|
||||
i = e + 1
|
||||
else
|
||||
push_token(res, token_type, text:usub(i))
|
||||
push_token(res, p.type, text:usub(i))
|
||||
break
|
||||
end
|
||||
end
|
||||
|
@ -320,10 +319,9 @@ function tokenizer.tokenize(incoming_syntax, text, state, resume)
|
|||
-- we're ending early in the middle of a delimiter, or
|
||||
-- just normally, upon finding a token.
|
||||
while subsyntax_info do
|
||||
local find_results = { find_text(text, subsyntax_info, i, true, true) }
|
||||
local s, e = find_results[1], find_results[2]
|
||||
local s, e = find_text(text, subsyntax_info, i, true, true)
|
||||
if s then
|
||||
push_tokens(res, current_syntax, subsyntax_info, text, find_results)
|
||||
push_token(res, subsyntax_info.type, text:usub(i, e))
|
||||
-- On finding unescaped delimiter, pop it.
|
||||
pop_subsyntax()
|
||||
i = e + 1
|
||||
|
@ -337,6 +335,14 @@ function tokenizer.tokenize(incoming_syntax, text, state, resume)
|
|||
for n, p in ipairs(current_syntax.patterns) do
|
||||
local find_results = { find_text(text, p, i, true, false) }
|
||||
if find_results[1] then
|
||||
-- Check for patterns successfully matching nothing
|
||||
if find_results[1] > find_results[2] then
|
||||
report_bad_pattern(core.warn, current_syntax, n,
|
||||
"Pattern successfully matched, but nothing was captured.")
|
||||
goto continue
|
||||
end
|
||||
|
||||
-- Check for patterns with mismatching number of `types`
|
||||
local type_is_table = type(p.type) == "table"
|
||||
local n_types = type_is_table and #p.type or 1
|
||||
if #find_results == 2 and type_is_table then
|
||||
|
@ -350,6 +356,7 @@ function tokenizer.tokenize(incoming_syntax, text, state, resume)
|
|||
report_bad_pattern(core.warn, current_syntax, n,
|
||||
"Too many token types: got %d needed %d.", n_types, #find_results - 1)
|
||||
end
|
||||
|
||||
-- matched pattern; make and add tokens
|
||||
push_tokens(res, current_syntax, p, text, find_results)
|
||||
-- update state if this was a start|end pattern pair
|
||||
|
@ -365,6 +372,7 @@ function tokenizer.tokenize(incoming_syntax, text, state, resume)
|
|||
i = find_results[2] + 1
|
||||
matched = true
|
||||
break
|
||||
::continue::
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -108,10 +108,6 @@ function View:get_h_scrollable_size()
|
|||
end
|
||||
|
||||
|
||||
function View:supports_text_input()
|
||||
return false
|
||||
end
|
||||
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@return boolean
|
||||
|
@ -142,14 +138,14 @@ function View:on_mouse_pressed(button, x, y, clicks)
|
|||
local result = self.v_scrollbar:on_mouse_pressed(button, x, y, clicks)
|
||||
if result then
|
||||
if result ~= true then
|
||||
self.scroll.to.y = result * (self:get_scrollable_size() - self.size.y)
|
||||
self.scroll.to.y = result * self:get_scrollable_size()
|
||||
end
|
||||
return true
|
||||
end
|
||||
result = self.h_scrollbar:on_mouse_pressed(button, x, y, clicks)
|
||||
if result then
|
||||
if result ~= true then
|
||||
self.scroll.to.x = result * (self:get_h_scrollable_size() - self.size.x)
|
||||
self.scroll.to.x = result * self:get_h_scrollable_size()
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
@ -177,7 +173,7 @@ function View:on_mouse_moved(x, y, dx, dy)
|
|||
result = self.v_scrollbar:on_mouse_moved(x, y, dx, dy)
|
||||
if result then
|
||||
if result ~= true then
|
||||
self.scroll.to.y = result * (self:get_scrollable_size() - self.size.y)
|
||||
self.scroll.to.y = result * self:get_scrollable_size()
|
||||
if not config.animate_drag_scroll then
|
||||
self:clamp_scroll_position()
|
||||
self.scroll.y = self.scroll.to.y
|
||||
|
@ -191,7 +187,7 @@ function View:on_mouse_moved(x, y, dx, dy)
|
|||
result = self.h_scrollbar:on_mouse_moved(x, y, dx, dy)
|
||||
if result then
|
||||
if result ~= true then
|
||||
self.scroll.to.x = result * (self:get_h_scrollable_size() - self.size.x)
|
||||
self.scroll.to.x = result * self:get_h_scrollable_size()
|
||||
if not config.animate_drag_scroll then
|
||||
self:clamp_scroll_position()
|
||||
self.scroll.x = self.scroll.to.x
|
||||
|
@ -248,23 +244,6 @@ function View:get_content_bounds()
|
|||
return x, y, x + self.size.x, y + self.size.y
|
||||
end
|
||||
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param dx number
|
||||
---@param dy number
|
||||
---@param i number
|
||||
function View:on_touch_moved(x, y, dx, dy, i)
|
||||
if not self.scrollable then return end
|
||||
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)
|
||||
|
||||
self.scroll.to.y = self.scroll.to.y + -dy
|
||||
self.scroll.to.x = self.scroll.to.x + -dx
|
||||
end
|
||||
|
||||
|
||||
---@return number x
|
||||
---@return number y
|
||||
|
@ -287,16 +266,12 @@ end
|
|||
function View:update_scrollbar()
|
||||
local v_scrollable = self:get_scrollable_size()
|
||||
self.v_scrollbar:set_size(self.position.x, self.position.y, self.size.x, self.size.y, v_scrollable)
|
||||
local v_percent = self.scroll.y/(v_scrollable - self.size.y)
|
||||
-- Avoid setting nan percent
|
||||
self.v_scrollbar:set_percent(v_percent == v_percent and v_percent or 0)
|
||||
self.v_scrollbar:set_percent(self.scroll.y/v_scrollable)
|
||||
self.v_scrollbar:update()
|
||||
|
||||
local h_scrollable = self:get_h_scrollable_size()
|
||||
self.h_scrollbar:set_size(self.position.x, self.position.y, self.size.x, self.size.y, h_scrollable)
|
||||
local h_percent = self.scroll.x/(h_scrollable - self.size.x)
|
||||
-- Avoid setting nan percent
|
||||
self.h_scrollbar:set_percent(h_percent == h_percent and h_percent or 0)
|
||||
self.h_scrollbar:set_percent(self.scroll.x/h_scrollable)
|
||||
self.h_scrollbar:update()
|
||||
end
|
||||
|
||||
|
|
|
@ -10,10 +10,6 @@ local RootView = require "core.rootview"
|
|||
local DocView = require "core.docview"
|
||||
local Doc = require "core.doc"
|
||||
|
||||
---Symbols cache of all open documents
|
||||
---@type table<core.doc, table>
|
||||
local cache = setmetatable({}, { __mode = "k" })
|
||||
|
||||
config.plugins.autocomplete = common.merge({
|
||||
-- Amount of characters that need to be written for autocomplete
|
||||
min_len = 3,
|
||||
|
@ -23,16 +19,8 @@ config.plugins.autocomplete = common.merge({
|
|||
max_suggestions = 100,
|
||||
-- Maximum amount of symbols to cache per document
|
||||
max_symbols = 4000,
|
||||
-- Which symbols to show on the suggestions list: global, local, related, none
|
||||
suggestions_scope = "global",
|
||||
-- Font size of the description box
|
||||
desc_font_size = 12,
|
||||
-- Do not show the icons associated to the suggestions
|
||||
hide_icons = false,
|
||||
-- Position where icons will be displayed on the suggestions list
|
||||
icon_position = "left",
|
||||
-- Do not show the additional information related to a suggestion
|
||||
hide_info = false,
|
||||
-- The config specification used by gui generators
|
||||
config_spec = {
|
||||
name = "Autocomplete",
|
||||
|
@ -72,26 +60,6 @@ config.plugins.autocomplete = common.merge({
|
|||
min = 1000,
|
||||
max = 10000
|
||||
},
|
||||
{
|
||||
label = "Suggestions Scope",
|
||||
description = "Which symbols to show on the suggestions list.",
|
||||
path = "suggestions_scope",
|
||||
type = "selection",
|
||||
default = "global",
|
||||
values = {
|
||||
{"All Documents", "global"},
|
||||
{"Current Document", "local"},
|
||||
{"Related Documents", "related"},
|
||||
{"Known Symbols", "none"}
|
||||
},
|
||||
on_apply = function(value)
|
||||
if value == "global" then
|
||||
for _, doc in ipairs(core.docs) do
|
||||
if cache[doc] then cache[doc] = nil end
|
||||
end
|
||||
end
|
||||
end
|
||||
},
|
||||
{
|
||||
label = "Description Font Size",
|
||||
description = "Font size of the description box.",
|
||||
|
@ -99,31 +67,6 @@ config.plugins.autocomplete = common.merge({
|
|||
type = "number",
|
||||
default = 12,
|
||||
min = 8
|
||||
},
|
||||
{
|
||||
label = "Hide Icons",
|
||||
description = "Do not show icons on the suggestions list.",
|
||||
path = "hide_icons",
|
||||
type = "toggle",
|
||||
default = false
|
||||
},
|
||||
{
|
||||
label = "Icons Position",
|
||||
description = "Position to display icons on the suggestions list.",
|
||||
path = "icon_position",
|
||||
type = "selection",
|
||||
default = "left",
|
||||
values = {
|
||||
{"Left", "left"},
|
||||
{"Right", "Right"}
|
||||
}
|
||||
},
|
||||
{
|
||||
label = "Hide Items Info",
|
||||
description = "Do not show the additional info related to each suggestion.",
|
||||
path = "hide_info",
|
||||
type = "toggle",
|
||||
default = false
|
||||
}
|
||||
}
|
||||
}, config.plugins.autocomplete)
|
||||
|
@ -133,7 +76,6 @@ local autocomplete = {}
|
|||
autocomplete.map = {}
|
||||
autocomplete.map_manually = {}
|
||||
autocomplete.on_close = nil
|
||||
autocomplete.icons = {}
|
||||
|
||||
-- Flag that indicates if the autocomplete box was manually triggered
|
||||
-- with the autocomplete.complete() function to prevent the suggestions
|
||||
|
@ -153,7 +95,6 @@ function autocomplete.add(t, manually_triggered)
|
|||
{
|
||||
text = text,
|
||||
info = info.info,
|
||||
icon = info.icon, -- Name of icon to show
|
||||
desc = info.desc, -- Description shown on item selected
|
||||
onhover = info.onhover, -- A callback called once when item is hovered
|
||||
onselect = info.onselect, -- A callback called when item is selected
|
||||
|
@ -178,35 +119,28 @@ end
|
|||
--
|
||||
-- Thread that scans open document symbols and cache them
|
||||
--
|
||||
local global_symbols = {}
|
||||
local max_symbols = config.plugins.autocomplete.max_symbols
|
||||
|
||||
core.add_thread(function()
|
||||
local function load_syntax_symbols(doc)
|
||||
if doc.syntax and not autocomplete.map["language_"..doc.syntax.name] then
|
||||
local symbols = {
|
||||
name = "language_"..doc.syntax.name,
|
||||
files = doc.syntax.files,
|
||||
items = {}
|
||||
}
|
||||
for name, type in pairs(doc.syntax.symbols) do
|
||||
symbols.items[name] = type
|
||||
local cache = setmetatable({}, { __mode = "k" })
|
||||
|
||||
local function get_syntax_symbols(symbols, doc)
|
||||
if doc.syntax then
|
||||
for sym in pairs(doc.syntax.symbols) do
|
||||
symbols[sym] = true
|
||||
end
|
||||
autocomplete.add(symbols)
|
||||
return symbols.items
|
||||
end
|
||||
return {}
|
||||
end
|
||||
|
||||
local function get_symbols(doc)
|
||||
local s = {}
|
||||
local syntax_symbols = load_syntax_symbols(doc)
|
||||
local max_symbols = config.plugins.autocomplete.max_symbols
|
||||
get_syntax_symbols(s, doc)
|
||||
if doc.disable_symbols then return s end
|
||||
local i = 1
|
||||
local symbols_count = 0
|
||||
while i <= #doc.lines do
|
||||
for sym in doc.lines[i]:gmatch(config.symbol_pattern) do
|
||||
if not s[sym] and not syntax_symbols[sym] then
|
||||
if not s[sym] then
|
||||
symbols_count = symbols_count + 1
|
||||
if symbols_count > max_symbols then
|
||||
s = nil
|
||||
|
@ -252,18 +186,14 @@ core.add_thread(function()
|
|||
}
|
||||
end
|
||||
-- update symbol set with doc's symbol set
|
||||
if config.plugins.autocomplete.suggestions_scope == "global" then
|
||||
for sym in pairs(cache[doc].symbols) do
|
||||
symbols[sym] = true
|
||||
end
|
||||
for sym in pairs(cache[doc].symbols) do
|
||||
symbols[sym] = true
|
||||
end
|
||||
coroutine.yield()
|
||||
end
|
||||
|
||||
-- update global symbols list
|
||||
if config.plugins.autocomplete.suggestions_scope == "global" then
|
||||
global_symbols = symbols
|
||||
end
|
||||
-- update symbols list
|
||||
autocomplete.add { name = "open-docs", items = symbols }
|
||||
|
||||
-- wait for next scan
|
||||
local valid = true
|
||||
|
@ -282,12 +212,14 @@ end)
|
|||
|
||||
|
||||
local partial = ""
|
||||
local suggestions_offset = 1
|
||||
local suggestions_idx = 1
|
||||
local suggestions = {}
|
||||
local last_line, last_col
|
||||
|
||||
|
||||
local function reset_suggestions()
|
||||
suggestions_offset = 1
|
||||
suggestions_idx = 1
|
||||
suggestions = {}
|
||||
|
||||
|
@ -310,50 +242,12 @@ local function update_suggestions()
|
|||
map = autocomplete.map_manually
|
||||
end
|
||||
|
||||
local assigned_sym = {}
|
||||
|
||||
-- get all relevant suggestions for given filename
|
||||
local items = {}
|
||||
for _, v in pairs(map) do
|
||||
if common.match_pattern(filename, v.files) then
|
||||
for _, item in pairs(v.items) do
|
||||
table.insert(items, item)
|
||||
assigned_sym[item.text] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Append the global, local or related text symbols if applicable
|
||||
local scope = config.plugins.autocomplete.suggestions_scope
|
||||
|
||||
if not triggered_manually then
|
||||
local text_symbols = nil
|
||||
|
||||
if scope == "global" then
|
||||
text_symbols = global_symbols
|
||||
elseif scope == "local" and cache[doc] and cache[doc].symbols then
|
||||
text_symbols = cache[doc].symbols
|
||||
elseif scope == "related" then
|
||||
for _, d in ipairs(core.docs) do
|
||||
if doc.syntax == d.syntax then
|
||||
if cache[d].symbols then
|
||||
for name in pairs(cache[d].symbols) do
|
||||
if not assigned_sym[name] then
|
||||
table.insert(items, setmetatable(
|
||||
{text = name, info = "normal"}, mt
|
||||
))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if text_symbols then
|
||||
for name in pairs(text_symbols) do
|
||||
if not assigned_sym[name] then
|
||||
table.insert(items, setmetatable({text = name, info = "normal"}, mt))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -369,6 +263,7 @@ local function update_suggestions()
|
|||
end
|
||||
end
|
||||
suggestions_idx = 1
|
||||
suggestions_offset = 1
|
||||
end
|
||||
|
||||
local function get_partial_symbol()
|
||||
|
@ -384,8 +279,10 @@ local function get_active_view()
|
|||
end
|
||||
end
|
||||
|
||||
local last_max_width = 0
|
||||
local function get_suggestions_rect(av)
|
||||
if #suggestions == 0 then
|
||||
last_max_width = 0
|
||||
return 0, 0, 0, 0
|
||||
end
|
||||
|
||||
|
@ -394,51 +291,49 @@ local function get_suggestions_rect(av)
|
|||
y = y + av:get_line_height() + style.padding.y
|
||||
local font = av:get_font()
|
||||
local th = font:get_height()
|
||||
local has_icons = false
|
||||
local hide_info = config.plugins.autocomplete.hide_info
|
||||
local hide_icons = config.plugins.autocomplete.hide_icons
|
||||
|
||||
local max_width = 0
|
||||
for _, s in ipairs(suggestions) do
|
||||
local w = font:get_width(s.text)
|
||||
if s.info and not hide_info then
|
||||
w = w + style.font:get_width(s.info) + style.padding.x
|
||||
end
|
||||
local icon = s.icon or s.info
|
||||
if not hide_icons and icon and autocomplete.icons[icon] then
|
||||
w = w + autocomplete.icons[icon].font:get_width(
|
||||
autocomplete.icons[icon].char
|
||||
) + (style.padding.x / 2)
|
||||
has_icons = true
|
||||
end
|
||||
max_width = math.max(max_width, w)
|
||||
end
|
||||
|
||||
local ah = config.plugins.autocomplete.max_height
|
||||
|
||||
local max_items = #suggestions
|
||||
if max_items > ah then
|
||||
max_items = ah
|
||||
local max_items = math.min(ah, #suggestions)
|
||||
|
||||
local show_count = math.min(#suggestions, ah)
|
||||
local start_index = math.max(suggestions_idx-(ah-1), 1)
|
||||
|
||||
local max_width = 0
|
||||
for i = start_index, start_index + show_count - 1 do
|
||||
local s = suggestions[i]
|
||||
local w = font:get_width(s.text)
|
||||
if s.info then
|
||||
w = w + style.font:get_width(s.info) + style.padding.x
|
||||
end
|
||||
max_width = math.max(max_width, w)
|
||||
end
|
||||
max_width = math.max(last_max_width, max_width)
|
||||
last_max_width = max_width
|
||||
|
||||
max_width = max_width + style.padding.x * 2
|
||||
x = x - style.padding.x
|
||||
|
||||
-- additional line to display total items
|
||||
max_items = max_items + 1
|
||||
|
||||
if max_width < 150 then
|
||||
max_width = 150
|
||||
if max_width > core.root_view.size.x then
|
||||
max_width = core.root_view.size.x
|
||||
end
|
||||
if max_width < 150 * SCALE then
|
||||
max_width = 150 * SCALE
|
||||
end
|
||||
|
||||
-- if portion not visiable to right, reposition to DocView right margin
|
||||
if (x - av.position.x) + max_width > av.size.x then
|
||||
x = (av.size.x + av.position.x) - max_width - (style.padding.x * 2)
|
||||
if x + max_width > core.root_view.size.x then
|
||||
x = (av.size.x + av.position.x) - max_width
|
||||
end
|
||||
|
||||
return
|
||||
x - style.padding.x,
|
||||
x,
|
||||
y - style.padding.y,
|
||||
max_width + style.padding.x * 2,
|
||||
max_items * (th + style.padding.y) + style.padding.y,
|
||||
has_icons
|
||||
max_width,
|
||||
max_items * (th + style.padding.y) + style.padding.y
|
||||
end
|
||||
|
||||
local function wrap_line(line, max_chars)
|
||||
|
@ -558,16 +453,15 @@ local function draw_suggestions_box(av)
|
|||
local ah = config.plugins.autocomplete.max_height
|
||||
|
||||
-- draw background rect
|
||||
local rx, ry, rw, rh, has_icons = get_suggestions_rect(av)
|
||||
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
|
||||
local show_count = #suggestions <= ah and #suggestions or ah
|
||||
local start_index = suggestions_idx > ah and (suggestions_idx-(ah-1)) or 1
|
||||
local hide_info = config.plugins.autocomplete.hide_info
|
||||
local show_count = math.min(#suggestions, ah)
|
||||
local start_index = suggestions_offset
|
||||
|
||||
for i=start_index, start_index+show_count-1, 1 do
|
||||
if not suggestions[i] then
|
||||
|
@ -575,44 +469,23 @@ local function draw_suggestions_box(av)
|
|||
end
|
||||
local s = suggestions[i]
|
||||
|
||||
local icon_l_padding, icon_r_padding = 0, 0
|
||||
|
||||
if has_icons then
|
||||
local icon = s.icon or s.info
|
||||
if icon and autocomplete.icons[icon] then
|
||||
local ifont = autocomplete.icons[icon].font
|
||||
local itext = autocomplete.icons[icon].char
|
||||
local icolor = autocomplete.icons[icon].color
|
||||
if i == suggestions_idx then
|
||||
icolor = style.accent
|
||||
elseif type(icolor) == "string" then
|
||||
icolor = style.syntax[icolor]
|
||||
end
|
||||
if config.plugins.autocomplete.icon_position == "left" then
|
||||
common.draw_text(
|
||||
ifont, icolor, itext, "left", rx + style.padding.x, y, rw, lh
|
||||
)
|
||||
icon_l_padding = ifont:get_width(itext) + (style.padding.x / 2)
|
||||
else
|
||||
common.draw_text(
|
||||
ifont, icolor, itext, "right", rx, y, rw - style.padding.x, lh
|
||||
)
|
||||
icon_r_padding = ifont:get_width(itext) + (style.padding.x / 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
local info_size = s.info and (style.font:get_width(s.info) + style.padding.x) or style.padding.x
|
||||
|
||||
local color = (i == suggestions_idx) and style.accent or style.text
|
||||
common.draw_text(
|
||||
font, color, s.text, "left",
|
||||
rx + icon_l_padding + style.padding.x, y, rw, lh
|
||||
)
|
||||
if s.info and not hide_info then
|
||||
-- Push clip to avoid that the suggestion text gets drawn over suggestion type/icon
|
||||
core.push_clip_rect(rx + style.padding.x, y, rw - info_size - style.padding.x, lh)
|
||||
local x_adv = common.draw_text(font, color, s.text, "left", rx + style.padding.x, y, rw, lh)
|
||||
core.pop_clip_rect()
|
||||
-- If the text wasn't fully visible, draw an ellipsis
|
||||
if x_adv > rx + rw - info_size then
|
||||
local ellipsis_size = font:get_width("…")
|
||||
local ell_x = rx + rw - info_size - ellipsis_size
|
||||
renderer.draw_rect(ell_x, y, ellipsis_size, lh, style.background3)
|
||||
common.draw_text(font, color, "…", "left", ell_x, y, ellipsis_size, lh)
|
||||
end
|
||||
if s.info then
|
||||
color = (i == suggestions_idx) and style.text or style.dim
|
||||
common.draw_text(
|
||||
style.font, color, s.info, "right",
|
||||
rx, y, rw - icon_r_padding - style.padding.x, lh
|
||||
)
|
||||
common.draw_text(style.font, color, s.info, "right", rx, y, rw - style.padding.x, lh)
|
||||
end
|
||||
y = y + lh
|
||||
if suggestions_idx == i then
|
||||
|
@ -773,31 +646,6 @@ function autocomplete.can_complete()
|
|||
return false
|
||||
end
|
||||
|
||||
---Register a font icon that can be assigned to completion items.
|
||||
---@param name string
|
||||
---@param character string
|
||||
---@param font? renderer.font
|
||||
---@param color? string | renderer.color A style.syntax[] name or specific color
|
||||
function autocomplete.add_icon(name, character, font, color)
|
||||
local color_type = type(color)
|
||||
assert(
|
||||
not color or color_type == "table"
|
||||
or (color_type == "string" and style.syntax[color]),
|
||||
"invalid icon color given"
|
||||
)
|
||||
autocomplete.icons[name] = {
|
||||
char = character,
|
||||
font = font or style.code_font,
|
||||
color = color or "keyword"
|
||||
}
|
||||
end
|
||||
|
||||
--
|
||||
-- Register built-in syntax symbol types icon
|
||||
--
|
||||
for name, _ in pairs(style.syntax) do
|
||||
autocomplete.add_icon(name, "M", style.icon_font, name)
|
||||
end
|
||||
|
||||
--
|
||||
-- Commands
|
||||
|
@ -811,6 +659,7 @@ command.add(predicate, {
|
|||
["autocomplete:complete"] = function(dv)
|
||||
local doc = dv.doc
|
||||
local item = suggestions[suggestions_idx]
|
||||
local text = item.text
|
||||
local inserted = false
|
||||
if item.onselect then
|
||||
inserted = item.onselect(suggestions_idx, item)
|
||||
|
@ -819,7 +668,7 @@ command.add(predicate, {
|
|||
local current_partial = get_partial_symbol()
|
||||
local sz = #current_partial
|
||||
|
||||
for idx, line1, col1, line2, col2 in doc:get_selections(true) do
|
||||
for _, line1, col1, line2, _ in doc:get_selections(true) do
|
||||
local n = col1 - 1
|
||||
local line = doc.lines[line1]
|
||||
for i = 1, sz + 1 do
|
||||
|
@ -840,10 +689,24 @@ command.add(predicate, {
|
|||
|
||||
["autocomplete:previous"] = function()
|
||||
suggestions_idx = (suggestions_idx - 2) % #suggestions + 1
|
||||
|
||||
local ah = math.min(config.plugins.autocomplete.max_height, #suggestions)
|
||||
if suggestions_offset > suggestions_idx then
|
||||
suggestions_offset = suggestions_idx
|
||||
elseif suggestions_offset + ah < suggestions_idx + 1 then
|
||||
suggestions_offset = suggestions_idx - ah + 1
|
||||
end
|
||||
end,
|
||||
|
||||
["autocomplete:next"] = function()
|
||||
suggestions_idx = (suggestions_idx % #suggestions) + 1
|
||||
|
||||
local ah = math.min(config.plugins.autocomplete.max_height, #suggestions)
|
||||
if suggestions_offset + ah < suggestions_idx + 1 then
|
||||
suggestions_offset = suggestions_idx - ah + 1
|
||||
elseif suggestions_offset > suggestions_idx then
|
||||
suggestions_offset = suggestions_idx
|
||||
end
|
||||
end,
|
||||
|
||||
["autocomplete:cycle"] = function()
|
||||
|
|
|
@ -69,7 +69,7 @@ function dirwatch:check(change_callback, ...)
|
|||
for _, doc in ipairs(core.docs) do
|
||||
if doc.abs_filename and (dir == common.dirname(doc.abs_filename) or dir == doc.abs_filename) then
|
||||
local info = system.get_file_info(doc.filename or "")
|
||||
if info and times[doc] ~= info.modified then
|
||||
if info and info.type == "file" and times[doc] ~= info.modified then
|
||||
if not doc:is_dirty() and not config.plugins.autoreload.always_show_nagview then
|
||||
reload_doc(doc)
|
||||
else
|
||||
|
|
|
@ -37,11 +37,7 @@ local function optimal_indent_from_stat(stat)
|
|||
elseif
|
||||
indent > stat[y]
|
||||
and
|
||||
(
|
||||
indent_occurrences_more_than_once(stat, y)
|
||||
or
|
||||
(y == count and stat[y] > 1)
|
||||
)
|
||||
indent_occurrences_more_than_once(stat, y)
|
||||
then
|
||||
score = 0
|
||||
break
|
||||
|
@ -122,10 +118,10 @@ local function get_comment_patterns(syntax, _loop)
|
|||
end
|
||||
if type(pattern.regex) == "table" then
|
||||
table.insert(comments, {
|
||||
"r", regex.compile(startp), regex.compile(pattern.regex[2]), r=startp
|
||||
"r", regex.compile(startp), regex.compile(pattern.regex[2])
|
||||
})
|
||||
elseif not_is_string then
|
||||
table.insert(comments, {"r", regex.compile(startp), r=startp})
|
||||
table.insert(comments, {"r", regex.compile(startp)})
|
||||
end
|
||||
end
|
||||
elseif pattern.syntax then
|
||||
|
@ -156,25 +152,6 @@ local function get_comment_patterns(syntax, _loop)
|
|||
table.insert(comments, {"p", "^%s*" .. block_comment[1], block_comment[2]})
|
||||
end
|
||||
end
|
||||
-- Put comments first and strings last
|
||||
table.sort(comments, function(c1, c2)
|
||||
local comment1, comment2 = false, false
|
||||
if
|
||||
(c1[1] == "p" and string.find(c1[2], "^%s*", 1, true))
|
||||
or
|
||||
(c1[1] == "r" and string.find(c1["r"], "^\\s*", 1, true))
|
||||
then
|
||||
comment1 = true
|
||||
end
|
||||
if
|
||||
(c2[1] == "p" and string.find(c2[2], "^%s*", 1, true))
|
||||
or
|
||||
(c2[1] == "r" and string.find(c2["r"], "^\\s*", 1, true))
|
||||
then
|
||||
comment2 = true
|
||||
end
|
||||
return comment1 and not comment2
|
||||
end)
|
||||
comments_cache[syntax] = comments
|
||||
if #comments > 0 then
|
||||
return comments
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
-- mod-version:3
|
||||
|
||||
local core = require "core"
|
||||
local style = require "core.style"
|
||||
local DocView = require "core.docview"
|
||||
local common = require "core.common"
|
||||
|
@ -13,7 +12,6 @@ config.plugins.drawwhitespace = common.merge({
|
|||
show_leading = true,
|
||||
show_trailing = true,
|
||||
show_middle = true,
|
||||
show_selected_only = false,
|
||||
|
||||
show_middle_min = 1,
|
||||
|
||||
|
@ -67,13 +65,6 @@ config.plugins.drawwhitespace = common.merge({
|
|||
type = "toggle",
|
||||
default = true,
|
||||
},
|
||||
{
|
||||
label = "Show Selected Only",
|
||||
description = "Only draw whitespaces if it is within a selection.",
|
||||
path = "show_selected_only",
|
||||
type = "toggle",
|
||||
default = false,
|
||||
},
|
||||
{
|
||||
label = "Show Trailing as Error",
|
||||
description = "Uses an error square to spot them easily, requires 'Show Trailing' enabled.",
|
||||
|
@ -302,41 +293,11 @@ function DocView:draw_line_text(idx, x, y)
|
|||
for i=1,#cache,4 do
|
||||
local tx = cache[i + 1] + x
|
||||
local tw = cache[i + 2]
|
||||
local sub = cache[i]
|
||||
local color = cache[i + 3]
|
||||
local partials = {}
|
||||
if config.plugins.drawwhitespace.show_selected_only and self.doc:has_any_selection() then
|
||||
for _, l1, c1, l2, c2 in self.doc:get_selections(true) do
|
||||
if idx > l1 and idx < l2 then
|
||||
-- Between selection lines, so everything is selected
|
||||
table.insert(partials, false)
|
||||
elseif idx == l1 and idx == l2 then
|
||||
-- Both ends of the selection are on the same line
|
||||
local _x1 = math.max(cache[i + 1], self:get_col_x_offset(idx, c1))
|
||||
local _x2 = math.min((cache[i + 1] + tw), self:get_col_x_offset(idx, c2))
|
||||
if _x1 < _x2 then
|
||||
table.insert(partials, {_x1 + x, 0, _x2 - _x1, math.huge})
|
||||
end
|
||||
elseif idx >= l1 and idx <= l2 then
|
||||
-- On one of the selection ends
|
||||
if idx == l1 then -- Start of the selection
|
||||
local _x = math.max(cache[i + 1], self:get_col_x_offset(idx, c1))
|
||||
table.insert(partials, {_x + x, 0, math.huge, math.huge})
|
||||
else -- End of the selection
|
||||
local _x = math.min((cache[i + 1] + tw), self:get_col_x_offset(idx, c2))
|
||||
table.insert(partials, {0, 0, _x + x, math.huge})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #partials == 0 and not config.plugins.drawwhitespace.show_selected_only then
|
||||
renderer.draw_text(font, sub, tx, ty, color)
|
||||
else
|
||||
for _, p in pairs(partials) do
|
||||
if p then core.push_clip_rect(table.unpack(p)) end
|
||||
renderer.draw_text(font, sub, tx, ty, color)
|
||||
if p then core.pop_clip_rect() end
|
||||
if tx <= x2 then
|
||||
local sub = cache[i]
|
||||
local color = cache[i + 3]
|
||||
if tx + tw >= x1 then
|
||||
tx = renderer.draw_text(font, sub, tx, ty, color)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,7 +5,8 @@ syntax.add {
|
|||
name = "C++",
|
||||
files = {
|
||||
"%.h$", "%.inl$", "%.cpp$", "%.cc$", "%.C$", "%.cxx$",
|
||||
"%.c++$", "%.hh$", "%.H$", "%.hxx$", "%.hpp$", "%.h++$"
|
||||
"%.c++$", "%.hh$", "%.H$", "%.hxx$", "%.hpp$", "%.h++$",
|
||||
"%.ino$"
|
||||
},
|
||||
comment = "//",
|
||||
block_comment = { "/*", "*/" },
|
||||
|
|
|
@ -20,10 +20,10 @@ local syntax = require "core.syntax"
|
|||
-- followed by pattern options, and anything that can
|
||||
-- be after a pattern.
|
||||
--
|
||||
-- Demo with some unit tests (click on the Unit Tests entry): https://regex101.com/r/R0w8Qw/1
|
||||
-- Demo with some unit tests (click on the Unit Tests entry): https://regex101.com/r/Vx5L5V/1
|
||||
-- Note that it has a couple of changes to make it work on that platform.
|
||||
local regex_pattern = {
|
||||
[=[/(?=(?!/)(?:(?>[^\\[\/]++|\\.|\[(?:[^\\\]]++|\\.)*+\])*+)++/[gmiyuvsd]*\s*[\n,;\)\]\}\.])()]=],
|
||||
[=[\/(?=(?!\/)(?:(?>[^\\[\/]++|\\.|\[(?:[^\\\]]++|\\.)*+\])*+)++\/[gmiyuvsd]*\s*(?:[\n,;\)\]\}\.]|\/[\/*]))()]=],
|
||||
"/()[gmiyuvsd]*", "\\"
|
||||
}
|
||||
|
||||
|
@ -57,18 +57,19 @@ syntax.add {
|
|||
comment = "//",
|
||||
block_comment = { "/*", "*/" },
|
||||
patterns = {
|
||||
{ pattern = "//.*", type = "comment" },
|
||||
{ pattern = { "/%*", "%*/" }, type = "comment" },
|
||||
{ regex = regex_pattern, syntax = inner_regex_syntax, type = {"string", "string"} },
|
||||
{ pattern = { '"', '"', '\\' }, type = "string" },
|
||||
{ pattern = { "'", "'", '\\' }, type = "string" },
|
||||
{ pattern = { "`", "`", '\\' }, type = "string" },
|
||||
{ pattern = "0x[%da-fA-F_]+n?()%s*()/?", type = {"number", "normal", "operator"} },
|
||||
{ pattern = "-?%d+[%d%.eE_n]*()%s*()/?", type = {"number", "normal", "operator"} },
|
||||
{ pattern = "-?%.?%d+()%s*()/?", type = {"number", "normal", "operator"} },
|
||||
{ pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" },
|
||||
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
|
||||
{ pattern = "[%a_][%w_]*()%s*()/?", type = {"symbol", "normal", "operator"} },
|
||||
{ pattern = "//.*", type = "comment" },
|
||||
{ pattern = { "/%*", "%*/" }, type = "comment" },
|
||||
{ regex = regex_pattern, syntax = inner_regex_syntax, type = {"string", "string"} },
|
||||
{ pattern = { '"', '"', '\\' }, type = "string" },
|
||||
{ pattern = { "'", "'", '\\' }, type = "string" },
|
||||
{ pattern = { "`", "`", '\\' }, type = "string" },
|
||||
-- Use (?:\/(?!\/|\*))? to avoid that a regex can start after a number, while also allowing // and /* comments
|
||||
{ regex = [[-?0[xXbBoO][\da-fA-F_]+n?()\s*()(?:\/(?!\/|\*))?]], type = {"number", "normal", "operator"} },
|
||||
{ regex = [[-?\d+[0-9.eE_n]*()\s*()(?:\/(?!\/|\*))?]], type = {"number", "normal", "operator"} },
|
||||
{ regex = [[-?\.?\d+()\s*()(?:\/(?!\/|\*))?]], type = {"number", "normal", "operator"} },
|
||||
{ pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" },
|
||||
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
|
||||
{ pattern = "[%a_][%w_]*", type = "symbol" },
|
||||
},
|
||||
symbols = {
|
||||
["async"] = "keyword",
|
||||
|
@ -92,6 +93,7 @@ syntax.add {
|
|||
["get"] = "keyword",
|
||||
["if"] = "keyword",
|
||||
["import"] = "keyword",
|
||||
["from"] = "keyword",
|
||||
["in"] = "keyword",
|
||||
["of"] = "keyword",
|
||||
["instanceof"] = "keyword",
|
||||
|
|
|
@ -128,7 +128,6 @@ syntax.add {
|
|||
{ pattern = { "```go", "```" }, type = "string", syntax = ".go" },
|
||||
{ pattern = { "```lobster", "```" }, type = "string", syntax = ".lobster" },
|
||||
{ pattern = { "```liquid", "```" }, type = "string", syntax = ".liquid" },
|
||||
{ pattern = { "```nix", "```" }, type = "string", syntax = ".nix" },
|
||||
{ pattern = { "```", "```" }, type = "string" },
|
||||
{ pattern = { "``", "``" }, type = "string" },
|
||||
{ pattern = { "%f[\\`]%`[%S]", "`" }, type = "string" },
|
||||
|
|
|
@ -3,7 +3,7 @@ local syntax = require "core.syntax"
|
|||
|
||||
syntax.add {
|
||||
name = "Python",
|
||||
files = { "%.py$", "%.pyw$", "%.rpy$" },
|
||||
files = { "%.py$", "%.pyw$", "%.rpy$", "%.pyi$" },
|
||||
headers = "^#!.*[ /]python",
|
||||
comment = "#",
|
||||
block_comment = { '"""', '"""' },
|
||||
|
@ -16,8 +16,8 @@ syntax.add {
|
|||
{ pattern = { "[ruU]?'''", "'''", '\\' }, type = "string" },
|
||||
{ pattern = { '[ruU]?"', '"', '\\' }, type = "string" },
|
||||
{ pattern = { "[ruU]?'", "'", '\\' }, type = "string" },
|
||||
{ pattern = "0x[%da-fA-F]+", type = "number" },
|
||||
{ pattern = "-?%d+[%d%.eE]*", type = "number" },
|
||||
{ pattern = "-?0[xboXBO][%da-fA-F_]+",type = "number" },
|
||||
{ pattern = "-?%d+[%d%.eE_]*", type = "number" },
|
||||
{ pattern = "-?%.?%d+", type = "number" },
|
||||
{ pattern = "[%+%-=/%*%^%%<>!~|&]", type = "operator" },
|
||||
{ pattern = "[%a_][%w_]*%f[(]", type = "function" },
|
||||
|
|
|
@ -15,8 +15,6 @@ config.plugins.lineguide = common.merge({
|
|||
-- 120,
|
||||
config.line_limit
|
||||
},
|
||||
use_custom_color = false,
|
||||
custom_color = style.selection,
|
||||
-- The config specification used by gui generators
|
||||
config_spec = {
|
||||
name = "Line Guide",
|
||||
|
@ -65,21 +63,7 @@ config.plugins.lineguide = common.merge({
|
|||
end
|
||||
return new_rulers
|
||||
end
|
||||
},
|
||||
{
|
||||
label = "Use Custom Color",
|
||||
description = "Enable the utilization of a custom line color.",
|
||||
path = "use_custom_color",
|
||||
type = "toggle",
|
||||
default = false
|
||||
},
|
||||
{
|
||||
label = "Custom Color",
|
||||
description = "Applied when the above toggle is enabled.",
|
||||
path = "custom_color",
|
||||
type = "color",
|
||||
default = style.selection
|
||||
},
|
||||
}
|
||||
}
|
||||
}, config.plugins.lineguide)
|
||||
|
||||
|
@ -102,12 +86,10 @@ function DocView:draw_overlay(...)
|
|||
and
|
||||
self:is(DocView)
|
||||
then
|
||||
local conf = config.plugins.lineguide
|
||||
local line_x = self:get_line_screen_position(1)
|
||||
local character_width = self:get_font():get_width("n")
|
||||
local ruler_width = config.plugins.lineguide.width
|
||||
local ruler_color = conf.use_custom_color and conf.custom_color
|
||||
or (style.guide or style.selection)
|
||||
local ruler_color = style.guide or style.selection
|
||||
|
||||
for k,v in ipairs(config.plugins.lineguide.rulers) do
|
||||
local ruler = get_ruler(v)
|
||||
|
|
|
@ -37,7 +37,7 @@ local function find_all_matches_in_file(t, filename, fn)
|
|||
table.insert(t, { file = filename, text = (start_index > 1 and "..." or "") .. line:sub(start_index, 256 + start_index), line = n, col = s })
|
||||
core.redraw = true
|
||||
end
|
||||
if n % 100 == 0 then coroutine.yield(0) end
|
||||
if n % 100 == 0 then coroutine.yield() end
|
||||
n = n + 1
|
||||
core.redraw = true
|
||||
end
|
||||
|
|
|
@ -48,7 +48,7 @@ end
|
|||
|
||||
function ToolbarView:get_icon_width()
|
||||
local max_width = 0
|
||||
for i,v in ipairs(self.toolbar_commands) do max_width = math.max(max_width, (v.font or self.toolbar_font):get_width(v.symbol)) end
|
||||
for i,v in ipairs(self.toolbar_commands) do max_width = math.max(max_width, self.toolbar_font:get_width(v.symbol)) end
|
||||
return max_width
|
||||
end
|
||||
|
||||
|
@ -83,7 +83,7 @@ function ToolbarView:draw()
|
|||
|
||||
for item, x, y, w, h in self:each_item() do
|
||||
local color = item == self.hovered_item and command.is_valid(item.command) and style.text or style.dim
|
||||
common.draw_text(item.font or self.toolbar_font, color, item.symbol, nil, x, y, 0, h)
|
||||
common.draw_text(self.toolbar_font, color, item.symbol, nil, x, y, 0, h)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -100,16 +100,6 @@ function ToolbarView:on_mouse_pressed(button, x, y, clicks)
|
|||
end
|
||||
|
||||
|
||||
function ToolbarView:on_mouse_left()
|
||||
ToolbarView.super.on_mouse_left(self)
|
||||
if self.tooltip then
|
||||
core.status_view:remove_tooltip()
|
||||
self.tooltip = false
|
||||
end
|
||||
self.hovered_item = nil
|
||||
end
|
||||
|
||||
|
||||
function ToolbarView:on_mouse_moved(px, py, ...)
|
||||
if not self.visible then return end
|
||||
ToolbarView.super.on_mouse_moved(self, px, py, ...)
|
||||
|
|
|
@ -9,15 +9,10 @@ local View = require "core.view"
|
|||
local ContextMenu = require "core.contextmenu"
|
||||
local RootView = require "core.rootview"
|
||||
local CommandView = require "core.commandview"
|
||||
local DocView = require "core.docview"
|
||||
|
||||
config.plugins.treeview = common.merge({
|
||||
-- Default treeview width
|
||||
size = 200 * SCALE,
|
||||
highlight_focused_file = true,
|
||||
expand_dirs_to_focused_file = false,
|
||||
scroll_to_focused_file = false,
|
||||
animate_scroll_to_focused_file = true
|
||||
size = 200 * SCALE
|
||||
}, config.plugins.treeview)
|
||||
|
||||
local tooltip_offset = style.font:get_height()
|
||||
|
@ -51,7 +46,7 @@ function TreeView:new()
|
|||
self.target_size = config.plugins.treeview.size
|
||||
self.cache = {}
|
||||
self.tooltip = { x = 0, y = 0, begin = 0, alpha = 0 }
|
||||
self.last_scroll_y = 0
|
||||
self.cursor_pos = { x = 0, y = 0 }
|
||||
|
||||
self.item_icon_width = 0
|
||||
self.item_text_spacing = 0
|
||||
|
@ -88,7 +83,7 @@ function TreeView:get_cached(dir, item, dirname)
|
|||
else
|
||||
t.filename = item.filename
|
||||
t.depth = get_depth(item.filename)
|
||||
t.abs_filename = dirname .. PATHSEP .. item.filename
|
||||
t.abs_filename = common.basepath(dirname) .. item.filename
|
||||
end
|
||||
t.name = basename
|
||||
t.type = item.type
|
||||
|
@ -174,73 +169,20 @@ function TreeView:each_item()
|
|||
end
|
||||
|
||||
|
||||
function TreeView:set_selection(selection, selection_y, center, instant)
|
||||
function TreeView:set_selection(selection, selection_y)
|
||||
self.selected_item = selection
|
||||
if selection and selection_y
|
||||
and (selection_y <= 0 or selection_y >= self.size.y) then
|
||||
|
||||
local lh = self:get_item_height()
|
||||
if not center and selection_y >= self.size.y - lh then
|
||||
if selection_y >= self.size.y - lh then
|
||||
selection_y = selection_y - self.size.y + lh
|
||||
end
|
||||
if center then
|
||||
selection_y = selection_y - (self.size.y - lh) / 2
|
||||
end
|
||||
local _, y = self:get_content_offset()
|
||||
self.scroll.to.y = selection_y - y
|
||||
self.scroll.to.y = common.clamp(self.scroll.to.y, 0, self:get_scrollable_size() - self.size.y)
|
||||
if instant then
|
||||
self.scroll.y = self.scroll.to.y
|
||||
end
|
||||
self.scroll.to.y = selection and (selection_y - y)
|
||||
end
|
||||
end
|
||||
|
||||
---Sets the selection to the file with the specified path.
|
||||
---
|
||||
---@param path string #Absolute path of item to select
|
||||
---@param expand boolean #Expand dirs leading to the item
|
||||
---@param scroll_to boolean #Scroll to make the item visible
|
||||
---@param instant boolean #Don't animate the scroll
|
||||
---@return table? #The selected item
|
||||
function TreeView:set_selection_to_path(path, expand, scroll_to, instant)
|
||||
local to_select, to_select_y
|
||||
local let_it_finish, done
|
||||
::restart::
|
||||
for item, x,y,w,h in self:each_item() do
|
||||
if not done then
|
||||
if item.type == "dir" then
|
||||
local _, to = string.find(path, item.abs_filename..PATHSEP, 1, true)
|
||||
if to and to == #item.abs_filename + #PATHSEP then
|
||||
to_select, to_select_y = item, y
|
||||
if expand and not item.expanded then
|
||||
-- Use TreeView:toggle_expand to update the directory structure.
|
||||
-- Directly using item.expanded doesn't update the cached tree.
|
||||
self:toggle_expand(true, item)
|
||||
-- Because we altered the size of the TreeView
|
||||
-- and because TreeView:get_scrollable_size uses self.count_lines
|
||||
-- which gets updated only when TreeView:each_item finishes,
|
||||
-- we can't stop here or we risk that the scroll
|
||||
-- gets clamped by View:clamp_scroll_position.
|
||||
let_it_finish = true
|
||||
-- We need to restart the process because if TreeView:toggle_expand
|
||||
-- altered the cache, TreeView:each_item risks looping indefinitely.
|
||||
goto restart
|
||||
end
|
||||
end
|
||||
else
|
||||
if item.abs_filename == path then
|
||||
to_select, to_select_y = item, y
|
||||
done = true
|
||||
if not let_it_finish then break end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if to_select then
|
||||
self:set_selection(to_select, scroll_to and to_select_y, true, instant)
|
||||
end
|
||||
return to_select
|
||||
end
|
||||
|
||||
|
||||
function TreeView:get_text_bounding_box(item, x, y, w, h)
|
||||
local icon_width = style.icon_font:get_width("D")
|
||||
|
@ -251,9 +193,10 @@ function TreeView:get_text_bounding_box(item, x, y, w, h)
|
|||
end
|
||||
|
||||
|
||||
|
||||
function TreeView:on_mouse_moved(px, py, ...)
|
||||
if not self.visible then return end
|
||||
self.cursor_pos.x = px
|
||||
self.cursor_pos.y = py
|
||||
if TreeView.super.on_mouse_moved(self, px, py, ...) then
|
||||
-- mouse movement handled by the View (scrollbar)
|
||||
self.hovered_item = nil
|
||||
|
@ -280,12 +223,6 @@ function TreeView:on_mouse_moved(px, py, ...)
|
|||
end
|
||||
|
||||
|
||||
function TreeView:on_mouse_left()
|
||||
TreeView.super.on_mouse_left(self)
|
||||
self.hovered_item = nil
|
||||
end
|
||||
|
||||
|
||||
function TreeView:update()
|
||||
-- update width
|
||||
local dest = self.visible and self.target_size or 0
|
||||
|
@ -296,7 +233,7 @@ function TreeView:update()
|
|||
self:move_towards(self.size, "x", dest, nil, "treeview")
|
||||
end
|
||||
|
||||
if self.size.x == 0 or self.size.y == 0 or not self.visible then return end
|
||||
if not self.visible then return end
|
||||
|
||||
local duration = system.get_time() - self.tooltip.begin
|
||||
if self.hovered_item and self.tooltip.x and duration > tooltip_delay then
|
||||
|
@ -309,30 +246,10 @@ function TreeView:update()
|
|||
self.item_text_spacing = style.icon_font:get_width("f") / 2
|
||||
|
||||
-- this will make sure hovered_item is updated
|
||||
local dy = math.abs(self.last_scroll_y - self.scroll.y)
|
||||
if dy > 0 then
|
||||
self:on_mouse_moved(core.root_view.mouse.x, core.root_view.mouse.y, 0, 0)
|
||||
self.last_scroll_y = self.scroll.y
|
||||
end
|
||||
|
||||
local config = config.plugins.treeview
|
||||
if config.highlight_focused_file then
|
||||
-- Try to only highlight when we actually change tabs
|
||||
local current_node = core.root_view:get_active_node()
|
||||
local current_active_view = core.active_view
|
||||
if current_node and not current_node.locked
|
||||
and current_active_view ~= self and current_active_view ~= self.last_active_view then
|
||||
self.selected_item = nil
|
||||
self.last_active_view = current_active_view
|
||||
if DocView:is_extended_by(current_active_view) then
|
||||
local abs_filename = current_active_view.doc
|
||||
and current_active_view.doc.abs_filename or ""
|
||||
self:set_selection_to_path(abs_filename,
|
||||
config.expand_dirs_to_focused_file,
|
||||
config.scroll_to_focused_file,
|
||||
not config.animate_scroll_to_focused_file)
|
||||
end
|
||||
end
|
||||
-- we don't want events when the thing is scrolling fast
|
||||
local dy = math.abs(self.scroll.to.y - self.scroll.y)
|
||||
if self.scroll.to.y ~= 0 and dy < self:get_item_height() then
|
||||
self:on_mouse_moved(self.cursor_pos.x, self.cursor_pos.y, 0, 0)
|
||||
end
|
||||
|
||||
TreeView.super.update(self)
|
||||
|
@ -505,8 +422,8 @@ function TreeView:get_previous(item)
|
|||
end
|
||||
|
||||
|
||||
function TreeView:toggle_expand(toggle, item)
|
||||
item = item or self.selected_item
|
||||
function TreeView:toggle_expand(toggle)
|
||||
local item = self.selected_item
|
||||
|
||||
if not item then return end
|
||||
|
||||
|
@ -524,11 +441,6 @@ function TreeView:toggle_expand(toggle, item)
|
|||
end
|
||||
|
||||
|
||||
function TreeView:open_doc(filename)
|
||||
core.root_view:open_doc(core.open_doc(filename))
|
||||
end
|
||||
|
||||
|
||||
-- init
|
||||
local view = TreeView()
|
||||
local node = core.root_view:get_active_node()
|
||||
|
@ -707,7 +619,8 @@ command.add(
|
|||
if core.last_active_view and core.active_view == view then
|
||||
core.set_active_view(core.last_active_view)
|
||||
end
|
||||
view:open_doc(core.normalize_to_project_dir(item.abs_filename))
|
||||
local doc_filename = core.normalize_to_project_dir(item.abs_filename)
|
||||
core.root_view:open_doc(core.open_doc(doc_filename))
|
||||
end)
|
||||
end
|
||||
end,
|
||||
|
@ -753,26 +666,6 @@ command.add(
|
|||
view:toggle_expand(true)
|
||||
end
|
||||
end,
|
||||
|
||||
["treeview-context:show"] = function()
|
||||
if view.hovered_item then
|
||||
menu:show(core.root_view.mouse.x, core.root_view.mouse.y)
|
||||
return
|
||||
end
|
||||
|
||||
local item = view.selected_item
|
||||
if not item then return end
|
||||
|
||||
local x, y
|
||||
for _i, _x, _y, _w, _h in view:each_item() do
|
||||
if _i == item then
|
||||
x = _x + _w / 2
|
||||
y = _y + _h / 2
|
||||
break
|
||||
end
|
||||
end
|
||||
menu:show(x, y)
|
||||
end
|
||||
})
|
||||
|
||||
|
||||
|
@ -786,7 +679,7 @@ command.add(
|
|||
local relfilename = item.filename
|
||||
if item.dir_name ~= core.project_dir then
|
||||
-- add secondary project dirs names to the file path to show
|
||||
relfilename = common.basename(item.dir_name) .. PATHSEP .. relfilename
|
||||
relfilename = common.basepath(common.basename(item.dir_name)) .. PATHSEP .. relfilename
|
||||
end
|
||||
local file_info = system.get_file_info(filename)
|
||||
local file_type = file_info.type == "dir" and "Directory" or "File"
|
||||
|
@ -831,7 +724,7 @@ command.add(
|
|||
submit = function(filename)
|
||||
local abs_filename = filename
|
||||
if not common.is_absolute_path(filename) then
|
||||
abs_filename = item.dir_name .. PATHSEP .. filename
|
||||
abs_filename = common.basepath(item.dir_name) .. filename
|
||||
end
|
||||
local res, err = os.rename(old_abs_filename, abs_filename)
|
||||
if res then -- successfully renamed
|
||||
|
@ -861,12 +754,12 @@ command.add(
|
|||
core.command_view:enter("Filename", {
|
||||
text = text,
|
||||
submit = function(filename)
|
||||
local doc_filename = item.dir_name .. PATHSEP .. filename
|
||||
local doc_filename = common.basepath(item.dir_name) .. filename
|
||||
core.log(doc_filename)
|
||||
local file = io.open(doc_filename, "a+")
|
||||
file:write("")
|
||||
file:close()
|
||||
view:open_doc(doc_filename)
|
||||
core.root_view:open_doc(core.open_doc(doc_filename))
|
||||
core.log("Created %s", doc_filename)
|
||||
end,
|
||||
suggest = function(text)
|
||||
|
@ -883,7 +776,7 @@ command.add(
|
|||
core.command_view:enter("Folder Name", {
|
||||
text = text,
|
||||
submit = function(filename)
|
||||
local dir_path = item.dir_name .. PATHSEP .. filename
|
||||
local dir_path = common.basepath(item.dir_name) .. filename
|
||||
common.mkdirp(dir_path)
|
||||
core.log("Created %s", dir_path)
|
||||
end,
|
||||
|
@ -896,10 +789,12 @@ command.add(
|
|||
["treeview:open-in-system"] = function(item)
|
||||
if PLATFORM == "Windows" then
|
||||
system.exec(string.format("start \"\" %q", item.abs_filename))
|
||||
elseif string.find(PLATFORM, "Mac") then
|
||||
elseif string.find(PLATFORM, "Mac") or PLATFORM == "MorphOS" then
|
||||
system.exec(string.format("open %q", item.abs_filename))
|
||||
elseif PLATFORM == "Linux" or string.find(PLATFORM, "BSD") then
|
||||
system.exec(string.format("xdg-open %q", item.abs_filename))
|
||||
elseif PLATFORM == "AmigaOS 4" then
|
||||
system.exec(string.format("WBRUN %q SHOW=all VIEWBY=name", item.abs_filename))
|
||||
end
|
||||
end
|
||||
})
|
||||
|
@ -933,25 +828,6 @@ command.add(function()
|
|||
})
|
||||
|
||||
|
||||
command.add(
|
||||
function()
|
||||
return menu.show_context_menu == true and core.active_view:is(TreeView)
|
||||
end, {
|
||||
["treeview-context:focus-previous"] = function()
|
||||
menu:focus_previous()
|
||||
end,
|
||||
["treeview-context:focus-next"] = function()
|
||||
menu:focus_next()
|
||||
end,
|
||||
["treeview-context:hide"] = function()
|
||||
menu:hide()
|
||||
end,
|
||||
["treeview-context:on-selected"] = function()
|
||||
menu:call_selected_item()
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
keymap.add {
|
||||
["ctrl+\\"] = "treeview:toggle",
|
||||
["up"] = "treeview:previous",
|
||||
|
@ -967,15 +843,6 @@ keymap.add {
|
|||
["ctrl+lclick"] = "treeview:new-folder"
|
||||
}
|
||||
|
||||
keymap.add {
|
||||
["menu"] = "treeview-context:show",
|
||||
["return"] = "treeview-context:on-selected",
|
||||
["up"] = "treeview-context:focus-previous",
|
||||
["down"] = "treeview-context:focus-next",
|
||||
["escape"] = "treeview-context:hide"
|
||||
}
|
||||
|
||||
|
||||
-- The config specification used by gui generators
|
||||
config.plugins.treeview.config_spec = {
|
||||
name = "Treeview",
|
||||
|
|
|
@ -7,7 +7,7 @@ local LogView = require "core.logview"
|
|||
|
||||
local function workspace_files_for(project_dir)
|
||||
local basename = common.basename(project_dir)
|
||||
local workspace_dir = USERDIR .. PATHSEP .. "ws"
|
||||
local workspace_dir = common.basepath(USERDIR) .. "ws"
|
||||
local info_wsdir = system.get_file_info(workspace_dir)
|
||||
if not info_wsdir then
|
||||
local ok, err = system.mkdir(workspace_dir)
|
||||
|
@ -22,7 +22,7 @@ local function workspace_files_for(project_dir)
|
|||
if file:sub(1, n) == basename then
|
||||
local id = tonumber(file:sub(n + 1):match("^-(%d+)$"))
|
||||
if id then
|
||||
coroutine.yield(workspace_dir .. PATHSEP .. file, id)
|
||||
coroutine.yield(common.basepath(workspace_dir) .. file, id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -52,7 +52,7 @@ local function get_workspace_filename(project_dir)
|
|||
id = id + 1
|
||||
end
|
||||
local basename = common.basename(project_dir)
|
||||
return USERDIR .. PATHSEP .. "ws" .. PATHSEP .. basename .. "-" .. tostring(id)
|
||||
return common.basepath(USERDIR) .. "ws" .. PATHSEP .. basename .. "-" .. tostring(id)
|
||||
end
|
||||
|
||||
|
||||
|
@ -166,7 +166,7 @@ local function load_node(node, t)
|
|||
active_view = view
|
||||
end
|
||||
if not view:is(DocView) then
|
||||
view.scroll = v.scroll
|
||||
view.scroll = v.scroll
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
project('lite-xl',
|
||||
['c'],
|
||||
version : '2.1.1',
|
||||
version : '2.1.4',
|
||||
license : 'MIT',
|
||||
meson_version : '>= 0.56',
|
||||
default_options : [
|
||||
|
@ -101,7 +101,7 @@ if not get_option('source-only')
|
|||
endforeach
|
||||
else
|
||||
lua_dep = dependency('', fallback: ['lua', 'lua_dep'], required : true,
|
||||
default_options: default_fallback_options + ['default_library=static', 'line_editing=disabled', 'interpreter=false']
|
||||
default_options: default_fallback_options + ['default_library=static', 'line_editing=false', 'interpreter=false']
|
||||
)
|
||||
endif
|
||||
|
||||
|
@ -208,10 +208,10 @@ else
|
|||
install_data('resources/icons/lite-xl.svg',
|
||||
install_dir : 'share/icons/hicolor/scalable/apps'
|
||||
)
|
||||
install_data('resources/linux/com.lite_xl.LiteXL.desktop',
|
||||
install_data('resources/linux/org.lite_xl.lite_xl.desktop',
|
||||
install_dir : 'share/applications'
|
||||
)
|
||||
install_data('resources/linux/com.lite_xl.LiteXL.appdata.xml',
|
||||
install_data('resources/linux/org.lite_xl.lite_xl.appdata.xml',
|
||||
install_dir : 'share/metainfo'
|
||||
)
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
; Lite-XL AutoInstall
|
||||
; $VER: Lite-XL AutoInstall 1.0 (15.02.2024)
|
||||
|
||||
; Get the path to the executable from the ENV variable
|
||||
Set litexlPath `GetEnv AppDir/lite-xl`
|
||||
|
||||
copy LiteXL2/#? "$litexlPath" CLONE ALL
|
||||
|
||||
; Free the variable
|
||||
UnSet litexlPath
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,29 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#02103d" }
|
||||
style.background2 = { common.color "#02103d" }
|
||||
style.background3 = { common.color "#02103d" }
|
||||
style.text = { common.color "#0f6773" }
|
||||
style.caret = { common.color "#6a8ca8" }
|
||||
style.accent = { common.color "#6a8ca8" }
|
||||
style.dim = { common.color "#303030" }
|
||||
style.divider = { common.color "#151515" }
|
||||
style.selection = { common.color "#242424" }
|
||||
style.line_number = { common.color "#252525" }
|
||||
style.line_number2 = { common.color "#444444" }
|
||||
style.line_highlight = { common.color "#101010" }
|
||||
style.scrollbar = { common.color "#252525" }
|
||||
style.scrollbar2 = { common.color "#444444" }
|
||||
|
||||
style.syntax = {}
|
||||
style.syntax["normal"] = { common.color "#a0a0a0" }
|
||||
style.syntax["symbol"] = { common.color "#a0a0a0" }
|
||||
style.syntax["comment"] = { common.color "#404040" }
|
||||
style.syntax["keyword"] = { common.color "#dfdfdf" }
|
||||
style.syntax["keyword2"] = { common.color "#dfdfdf" }
|
||||
style.syntax["number"] = { common.color "#dfdfdf" }
|
||||
style.syntax["literal"] = { common.color "#dfdfdf" }
|
||||
style.syntax["string"] = { common.color "#132a52" }
|
||||
style.syntax["operator"] = { common.color "#01A870" }
|
||||
style.syntax["function"] = { common.color "#01A870" }
|
|
@ -0,0 +1,48 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
-- App --
|
||||
style.background = { common.color "#222831" }
|
||||
style.background2 = { common.color "#1e232b" }
|
||||
style.background3 = { common.color "#1e232b" }
|
||||
style.text = { common.color "#dfe2e7" }
|
||||
style.caret = { common.color "#dfe2e7" }
|
||||
style.accent = { common.color "#e2e4e9" }
|
||||
style.dim = { common.color "#8893a5" }
|
||||
style.divider = { common.color "#1e232b" }
|
||||
style.selection = { common.color "#2c3440" }
|
||||
style.line_number = { common.color "#8893a5" }
|
||||
style.line_number2 = { common.color "#8893a5" }
|
||||
style.line_highlight = { common.color "#242a34" }
|
||||
style.scrollbar = { common.color "#2c3440" }
|
||||
style.scrollbar2 = { common.color "#f5ad44" }
|
||||
style.scrollbar_track = { common.color "#00000000" }
|
||||
style.nagbar = { common.color "#db504a" }
|
||||
style.nagbar_text = { common.color "#dfe2e7" }
|
||||
style.nagbar_dim = { common.color "rgba(0, 0, 0, 0.45)" }
|
||||
style.drag_overlay = { common.color "#dfe2e733" }
|
||||
style.drag_overlay_tab = { common.color "#f5ad44" }
|
||||
style.good = { common.color "#47e2b1" }
|
||||
style.warn = { common.color "#f5ad44" }
|
||||
style.error = { common.color "#db504a" }
|
||||
style.modified = { common.color "#448bf5" }
|
||||
|
||||
-- Syntax --
|
||||
style.syntax = {}
|
||||
style.syntax["normal"] = { common.color "#dfe2e7" }
|
||||
style.syntax["symbol"] = { common.color "#dfe2e7" }
|
||||
style.syntax["comment"] = { common.color "#8893a5" }
|
||||
style.syntax["keyword"] = { common.color "#448bf5" }
|
||||
style.syntax["keyword2"] = { common.color "#f5ad44" }
|
||||
style.syntax["number"] = { common.color "#f5ad44" }
|
||||
style.syntax["literal"] = { common.color "#45e1df" }
|
||||
style.syntax["string"] = { common.color "#f5ad44" }
|
||||
style.syntax["operator"] = { common.color "#dfe2e7" }
|
||||
style.syntax["function"] = { common.color "#f786aa" }
|
||||
|
||||
-- Lint+ --
|
||||
style.lint = {}
|
||||
style.lint["info"] = { common.color "#448bf5" }
|
||||
style.lint["hint"] = { common.color "#47e2b1" }
|
||||
style.lint["warning"] = { common.color "#f5ad44" }
|
||||
style.lint["error"] = { common.color "#db504a" }
|
|
@ -0,0 +1,29 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#03071e" }
|
||||
style.background2 = { common.color "#03071e" }
|
||||
style.background3 = { common.color "#03071e" }
|
||||
style.text = { common.color "#ffa848" }
|
||||
style.caret = { common.color "#ffa848" }
|
||||
style.accent = { common.color "#ffb86c" }
|
||||
style.dim = { common.color "#4f526b" }
|
||||
style.divider = { common.color "#22242e" }
|
||||
style.selection = { common.color "#4c5163" }
|
||||
style.line_number = { common.color "#44475a" }
|
||||
style.line_number2 = { common.color "#717796" }
|
||||
style.line_highlight = { common.color "#2d303d" }
|
||||
style.scrollbar = { common.color "#44475a" }
|
||||
style.scrollbar2 = { common.color "#4c5163" }
|
||||
|
||||
style.syntax = {}
|
||||
style.syntax["normal"] = { common.color "#f5faff" }
|
||||
style.syntax["symbol"] = { common.color "#f5faff" }
|
||||
style.syntax["comment"] = { common.color "#081355" }
|
||||
style.syntax["keyword"] = { common.color "#fc0fc0" }
|
||||
style.syntax["keyword2"] = { common.color "#05e6fa" }
|
||||
style.syntax["number"] = { common.color "#7612c5" }
|
||||
style.syntax["literal"] = { common.color "#7612c5" }
|
||||
style.syntax["string"] = { common.color "#fdd017" }
|
||||
style.syntax["operator"] = { common.color "#fc0fc0" }
|
||||
style.syntax["function"] = { common.color "#05e6fa" }
|
|
@ -0,0 +1,28 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#073642" }
|
||||
style.background2 = { common.color "#073642" }
|
||||
style.background3 = { common.color "#073642" }
|
||||
style.text = { common.color "#00d1d1" }
|
||||
style.caret = { common.color "#f053f3" }
|
||||
style.accent = { common.color "#f053f3" }
|
||||
style.dim = { common.color "#586e75" }
|
||||
style.divider = { common.color "#6c71c4" }
|
||||
style.selection = { common.color "#415256" }
|
||||
style.line_number = { common.color "#586e75" }
|
||||
style.line_number2 = { common.color "#f053f3" }
|
||||
style.line_highlight = { common.color "#415256" }
|
||||
style.scrollbar = { common.color "#6c71c4" }
|
||||
style.scrollbar2 = { common.color "#6c71c4" }
|
||||
|
||||
style.syntax["normal"] = { common.color "#00d1d1" }
|
||||
style.syntax["symbol"] = { common.color "#00ff7f" }
|
||||
style.syntax["comment"] = { common.color "#6c71c4" }
|
||||
style.syntax["keyword"] = { common.color "#6c71c4" }
|
||||
style.syntax["keyword2"] = { common.color "#6c71c4" }
|
||||
style.syntax["number"] = { common.color "#00ff7f" }
|
||||
style.syntax["literal"] = { common.color "#1586d2" }
|
||||
style.syntax["string"] = { common.color "#f7f97d" }
|
||||
style.syntax["operator"] = { common.color "#00ff7f" }
|
||||
style.syntax["function"] = { common.color "#55ffff" }
|
|
@ -0,0 +1,28 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#282a36" }
|
||||
style.background2 = { common.color "#21222b" }
|
||||
style.background3 = { common.color "#21222b" }
|
||||
style.text = { common.color "#7b81a6" }
|
||||
style.caret = { common.color "#f8f8f0" }
|
||||
style.accent = { common.color "#8be9fd" }
|
||||
style.dim = { common.color "#4f5873" }
|
||||
style.divider = { common.color "#1f2029" }
|
||||
style.selection = { common.color "#44475a" }
|
||||
style.line_number = { common.color "#53576e" }
|
||||
style.line_number2 = { common.color "#f8f8f0" }
|
||||
style.line_highlight = { common.color "#313442" }
|
||||
style.scrollbar = { common.color "#44475a" }
|
||||
style.scrollbar2 = { common.color "#ff79c6" }
|
||||
|
||||
style.syntax["normal"] = { common.color "#f8f8f2" }
|
||||
style.syntax["symbol"] = { common.color "#f8f8f2" }
|
||||
style.syntax["comment"] = { common.color "#6272a4" }
|
||||
style.syntax["keyword"] = { common.color "#ff79c6" }
|
||||
style.syntax["keyword2"] = { common.color "#ff79c6" }
|
||||
style.syntax["number"] = { common.color "#bd93f9" }
|
||||
style.syntax["literal"] = { common.color "#f1fa8c" }
|
||||
style.syntax["string"] = { common.color "#f1fa8c" }
|
||||
style.syntax["operator"] = { common.color "#ff79c6" }
|
||||
style.syntax["function"] = { common.color "#50fa7b" }
|
|
@ -0,0 +1,38 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
math.randomseed(os.time())
|
||||
|
||||
local color = {
|
||||
math.random(90, 255),
|
||||
math.random(90, 255),
|
||||
math.random(90, 255),
|
||||
255
|
||||
}
|
||||
|
||||
style.background = { common.color "#151515" }
|
||||
style.background2 = { common.color "#151515" }
|
||||
style.background3 = { common.color "#151515" }
|
||||
style.text = { common.color "#707070" }
|
||||
style.caret = { common.color "#dfdfdf" }
|
||||
style.accent = { common.color "#d0d0d0" }
|
||||
style.dim = { common.color "#303030" }
|
||||
style.divider = { common.color "#151515" }
|
||||
style.selection = { common.color "#303030" }
|
||||
style.line_number = { common.color "#252525" }
|
||||
style.line_number2 = { common.color "#444444" }
|
||||
style.line_highlight = { common.color "#101010" }
|
||||
style.scrollbar = { common.color "#252525" }
|
||||
style.scrollbar2 = { common.color "#444444" }
|
||||
|
||||
style.syntax = {}
|
||||
style.syntax["normal"] = { common.color "#a0a0a0" }
|
||||
style.syntax["symbol"] = { common.color "#a0a0a0" }
|
||||
style.syntax["comment"] = { common.color "#404040" }
|
||||
style.syntax["keyword"] = { common.color "#dfdfdf" }
|
||||
style.syntax["keyword2"] = { common.color "#dfdfdf" }
|
||||
style.syntax["number"] = { common.color "#dfdfdf" }
|
||||
style.syntax["literal"] = { common.color "#dfdfdf" }
|
||||
style.syntax["string"] = { common.color "#dfdfdf" }
|
||||
style.syntax["operator"] = color
|
||||
style.syntax["function"] = color
|
|
@ -0,0 +1,29 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#151515" }
|
||||
style.background2 = { common.color "#151515" }
|
||||
style.background3 = { common.color "#151515" }
|
||||
style.text = { common.color "#707070" }
|
||||
style.caret = { common.color "#dfdfdf" }
|
||||
style.accent = { common.color "#d0d0d0" }
|
||||
style.dim = { common.color "#303030" }
|
||||
style.divider = { common.color "#151515" }
|
||||
style.selection = { common.color "#242424" }
|
||||
style.line_number = { common.color "#252525" }
|
||||
style.line_number2 = { common.color "#444444" }
|
||||
style.line_highlight = { common.color "#101010" }
|
||||
style.scrollbar = { common.color "#252525" }
|
||||
style.scrollbar2 = { common.color "#444444" }
|
||||
|
||||
style.syntax = {}
|
||||
style.syntax["normal"] = { common.color "#a0a0a0" }
|
||||
style.syntax["symbol"] = { common.color "#a0a0a0" }
|
||||
style.syntax["comment"] = { common.color "#404040" }
|
||||
style.syntax["keyword"] = { common.color "#dfdfdf" }
|
||||
style.syntax["keyword2"] = { common.color "#dfdfdf" }
|
||||
style.syntax["number"] = { common.color "#dfdfdf" }
|
||||
style.syntax["literal"] = { common.color "#dfdfdf" }
|
||||
style.syntax["string"] = { common.color "#dfdfdf" }
|
||||
style.syntax["operator"] = { common.color "#01A870" }
|
||||
style.syntax["function"] = { common.color "#01A870" }
|
|
@ -0,0 +1,38 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
-- GitHub color palette
|
||||
-- Ported by Andrey Proskurin (proskur1n)
|
||||
local bg = { common.color "#22272e" }
|
||||
local bg2 = { common.color "#2d333b" }
|
||||
local fg = { common.color "#adbac7" }
|
||||
local fgdim = { common.color "#768390" }
|
||||
local red = { common.color "#f47067" }
|
||||
local blue = { common.color "#6cb6ff" }
|
||||
local purple = { common.color "#dcbdfb" }
|
||||
|
||||
style.background = bg
|
||||
style.background2 = bg
|
||||
style.background3 = bg
|
||||
style.text = fg
|
||||
style.caret = red
|
||||
style.accent = blue
|
||||
style.dim = fgdim
|
||||
style.divider = { common.color "#444c56" }
|
||||
style.selection = { common.color "#2e4c77" }
|
||||
style.line_number = fgdim
|
||||
style.line_number2 = fg
|
||||
style.line_highlight = bg2
|
||||
style.scrol = fgdim
|
||||
style.scrollbar2 = fg
|
||||
|
||||
style.syntax["normal"] = fg
|
||||
style.syntax["symbol"] = fg
|
||||
style.syntax["comment"] = fgdim
|
||||
style.syntax["keyword"] = red
|
||||
style.syntax["keyword2"] = red
|
||||
style.syntax["number"] = blue
|
||||
style.syntax["literal"] = blue
|
||||
style.syntax["string"] = { common.color "#96d0ff" }
|
||||
style.syntax["operator"] = fg
|
||||
style.syntax["function"] = blue
|
|
@ -0,0 +1,41 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
-- GitHub color palette
|
||||
-- Ported by Andrey Proskurin (proskur1n)
|
||||
local bg = { common.color "#0d1117" }
|
||||
local bg2 = { common.color "#161925" }
|
||||
local fg = { common.color "#adbac7" }
|
||||
local fgdim = { common.color "#768390" }
|
||||
local red = { common.color "#f47067" }
|
||||
local blue = { common.color "#6cb6ff" }
|
||||
local purple = { common.color "#dcbdfb" }
|
||||
|
||||
style.background = bg
|
||||
style.background2 = bg
|
||||
style.background3 = bg2
|
||||
style.text = fg
|
||||
style.caret = red
|
||||
style.accent = blue
|
||||
style.dim = fgdim
|
||||
style.divider = { common.color "#444c56" }
|
||||
style.selection = { common.color "#2e4c77" }
|
||||
style.line_number = fgdim
|
||||
style.line_number2 = fg
|
||||
style.line_highlight = {common.color "#1e202e"}
|
||||
style.scrollbar = fgdim
|
||||
style.scrollbar2 = fg
|
||||
|
||||
style.syntax["normal"] = fg
|
||||
style.syntax["symbol"] = fg
|
||||
style.syntax["comment"] = fgdim
|
||||
style.syntax["keyword"] = red
|
||||
style.syntax["keyword2"] = red
|
||||
style.syntax["number"] = blue
|
||||
style.syntax["literal"] = blue
|
||||
style.syntax["string"] = { common.color "#96d0ff" }
|
||||
style.syntax["operator"] = fg
|
||||
style.syntax["function"] = blue
|
||||
|
||||
style.guide = { common.color "#404040" } -- indentguide
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#282828" }
|
||||
style.background2 = { common.color "#1d2021" }
|
||||
style.background3 = { common.color "#1d2021" }
|
||||
style.text = { common.color "#928374" }
|
||||
style.caret = { common.color "#fbf1c7" }
|
||||
style.accent = { common.color "#ebdbb2" }
|
||||
style.dim = { common.color "#928374" }
|
||||
style.divider = { common.color "#1d2021" }
|
||||
style.selection = { common.color "#3c3836" }
|
||||
style.line_number = { common.color "#928374" }
|
||||
style.line_number2 = { common.color "#ebdbb2" }
|
||||
style.line_highlight = { common.color "#32302f" }
|
||||
style.scrollbar = { common.color "#928374" }
|
||||
style.scrollbar2 = { common.color "#fbf1c7" }
|
||||
|
||||
style.syntax["normal"] = { common.color "#ebdbb2" }
|
||||
style.syntax["symbol"] = { common.color "#ebdbb2" }
|
||||
style.syntax["comment"] = { common.color "#928374" }
|
||||
style.syntax["keyword"] = { common.color "#fb4934" }
|
||||
style.syntax["keyword2"] = { common.color "#83a598" }
|
||||
style.syntax["number"] = { common.color "#d3869b" }
|
||||
style.syntax["literal"] = { common.color "#d3869b" }
|
||||
style.syntax["string"] = { common.color "#b8bb26" }
|
||||
style.syntax["operator"] = { common.color "#ebdbb2" }
|
||||
style.syntax["function"] = { common.color "#8ec07c" }
|
|
@ -0,0 +1,37 @@
|
|||
-- Colors from: https://github.com/nanotech/jellybeans.vim
|
||||
|
||||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#151515" }
|
||||
style.background2 = { common.color "#212121" }
|
||||
style.background3 = { common.color "#212121" }
|
||||
style.text = { common.color "#e8e8d3" }
|
||||
style.caret = { common.color "#e8e8d3" }
|
||||
style.accent = { common.color "#597bc5" } -- Text in autocomplete and command, col(>80) in satusbar
|
||||
style.dim = { common.color "#888888" } -- Text of nonactive tabs, prefix in log
|
||||
style.divider = { common.color "#151515" }
|
||||
style.selection = { common.color "#404040" }
|
||||
style.line_number = { common.color "#3b3b3b" }
|
||||
style.line_number2 = { common.color "#888888" } -- Number on line with caret
|
||||
style.line_highlight = { common.color "#191919"}
|
||||
style.scrollbar = { common.color "#2e2e2e" }
|
||||
style.scrollbar2 = { common.color "#3b3b3b" } -- Hovered
|
||||
|
||||
style.syntax["normal"] = { common.color "#6b8b9b" }
|
||||
style.syntax["symbol"] = { common.color "#e8e8d3" }
|
||||
style.syntax["comment"] = { common.color "#888888" }
|
||||
style.syntax["keyword"] = { common.color "#8197bf" } -- local function end, if case
|
||||
style.syntax["keyword2"] = { common.color "#FFB964" } -- self, int float
|
||||
style.syntax["number"] = { common.color "#cf6a4c" }
|
||||
style.syntax["literal"] = { common.color "#8FBFDC" }
|
||||
style.syntax["string"] = { common.color "#99ad6a" }
|
||||
style.syntax["operator"] = { common.color "#8FBFDC"} -- = + - / < >
|
||||
style.syntax["function"] = { common.color "#FAD07A" }
|
||||
|
||||
-- PLUGINS
|
||||
style.linter_warning = { common.color "#d8ad4c" } -- linter
|
||||
style.bracketmatch_color = { common.color "#8197bf" } -- bracketmatch
|
||||
style.guide = { common.color "#3b3b3b" }
|
||||
style.guide_highlight = { common.color "#5b5b5b" } -- indentguide
|
||||
style.guide_width = 1 -- indentguide
|
|
@ -0,0 +1,32 @@
|
|||
-- Liqube Dark Code for Lite <liqube.com>
|
||||
|
||||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#13171e" }
|
||||
style.background2 = { common.color "#21252b" }
|
||||
style.background3 = { common.color "#21252b" }
|
||||
style.text = { common.color "#abb2bf" }
|
||||
style.caret = { common.color "#abb2bf" }
|
||||
style.accent = { common.color "#ffffff" }
|
||||
style.dim = { common.color "#545e70" }
|
||||
style.divider = { common.color "#242223" }
|
||||
style.selection = { common.color "#3e4451" }
|
||||
style.line_number = { common.color "#323641" }
|
||||
style.line_number2 = { common.color "#596275" }
|
||||
style.line_highlight = { common.color "#1c1f25" }
|
||||
style.scrollbar = { common.color "#3d3f43" }
|
||||
style.scrollbar2 = { common.color "#595b5f" }
|
||||
style.guide = { common.color "#1c1f25" } -- indentguide
|
||||
|
||||
style.syntax["normal"] = { common.color "#abb2bf" }
|
||||
style.syntax["symbol"] = { common.color "#71a9d7" }
|
||||
style.syntax["comment"] = { common.color "#5c6370" }
|
||||
style.syntax["keyword"] = { common.color "#98c875" }
|
||||
style.syntax["keyword2"] = { common.color "#ffffff" }
|
||||
style.syntax["number"] = { common.color "#ffffff" }
|
||||
style.syntax["literal"] = { common.color "#ea5964" }
|
||||
style.syntax["string"] = { common.color "#ea5964" }
|
||||
style.syntax["operator"] = { common.color "#657085" }
|
||||
style.syntax["function"] = { common.color "#ffffff" }
|
||||
style.syntax["preprocessor"] = { common.color "#98c875" } -- thinking ahead
|
|
@ -0,0 +1,28 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#303841" }
|
||||
style.background2 = { common.color "#1d2227" }
|
||||
style.background3 = { common.color "#1d2227" }
|
||||
style.text = { common.color "#9ea191" }
|
||||
style.caret = { common.color "#61efce" }
|
||||
style.accent = { common.color "#ffd152" }
|
||||
style.dim = { common.color "#4c5863" }
|
||||
style.divider = { common.color "#242223" }
|
||||
style.selection = { common.color "#4c5863" }
|
||||
style.line_number = { common.color "#bfc5d0" }
|
||||
style.line_number2 = { common.color "#848b95" }
|
||||
style.line_highlight = { common.color "#303841" }
|
||||
style.scrollbar = { common.color "#696f75" }
|
||||
style.scrollbar2 = { common.color "#444b53" }
|
||||
|
||||
style.syntax["normal"] = { common.color "#d7dde9" }
|
||||
style.syntax["symbol"] = { common.color "#d8dee9" }
|
||||
style.syntax["comment"] = { common.color "#a6acb9" }
|
||||
style.syntax["keyword"] = { common.color "#e55e66" }
|
||||
style.syntax["keyword2"] = { common.color "#ef6179" }
|
||||
style.syntax["number"] = { common.color "#ffd152" }
|
||||
style.syntax["literal"] = { common.color "#e75550" }
|
||||
style.syntax["string"] = { common.color "#939d5d" }
|
||||
style.syntax["operator"] = { common.color "#c2674f" }
|
||||
style.syntax["function"] = { common.color "#6699ca" }
|
|
@ -0,0 +1,29 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#080808" }
|
||||
style.background2 = { common.color "#080808" }
|
||||
style.background3 = { common.color "#101010" }
|
||||
style.text = { common.color "#707070" }
|
||||
style.caret = { common.color "#ffffff" }
|
||||
style.accent = { common.color "#d0d0d0" }
|
||||
style.dim = { common.color "#303030" }
|
||||
style.divider = { common.color "#080808" }
|
||||
style.selection = { common.color "#242424" }
|
||||
style.line_number = { common.color "#202020" }
|
||||
style.line_number2 = { common.color "#707070" }
|
||||
style.line_highlight = { common.color "#101010" }
|
||||
style.scrollbar = { common.color "#252525" }
|
||||
style.scrollbar2 = { common.color "#303030" }
|
||||
|
||||
style.syntax = {}
|
||||
style.syntax["normal"] = { common.color "#a0a0a0" }
|
||||
style.syntax["symbol"] = { common.color "#a0a0a0" }
|
||||
style.syntax["comment"] = { common.color "#404040" }
|
||||
style.syntax["keyword"] = { common.color "#f0f0f0" }
|
||||
style.syntax["keyword2"] = { common.color "#f0f0f0" }
|
||||
style.syntax["number"] = { common.color "#f0f0f0" }
|
||||
style.syntax["literal"] = { common.color "#f0f0f0" }
|
||||
style.syntax["string"] = { common.color "#f0f0f0" }
|
||||
style.syntax["operator"] = { common.color "#f0f0f0" }
|
||||
style.syntax["function"] = { common.color "#a0a0a0" }
|
|
@ -0,0 +1,28 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#272822" }
|
||||
style.background2 = { common.color "#22231C" }
|
||||
style.background3 = { common.color "#22231C" }
|
||||
style.text = { common.color "#9ea191" }
|
||||
style.caret = { common.color "#F8F8F0" }
|
||||
style.accent = { common.color "#F8F8F2" }
|
||||
style.dim = { common.color "#5e6052" }
|
||||
style.divider = { common.color "#1b1c17" }
|
||||
style.selection = { common.color "#49483E" }
|
||||
style.line_number = { common.color "#75715E" }
|
||||
style.line_number2 = { common.color "#d2d0c6" }
|
||||
style.line_highlight = { common.color "#36372f" }
|
||||
style.scrollbar = { common.color "#49483E" }
|
||||
style.scrollbar2 = { common.color "#636254" }
|
||||
|
||||
style.syntax["normal"] = { common.color "#F8F8F2" }
|
||||
style.syntax["symbol"] = { common.color "#F8F8F2" }
|
||||
style.syntax["comment"] = { common.color "#75715E" }
|
||||
style.syntax["keyword"] = { common.color "#F92672" }
|
||||
style.syntax["keyword2"] = { common.color "#66DAEF" }
|
||||
style.syntax["number"] = { common.color "#AE81FF" }
|
||||
style.syntax["literal"] = { common.color "#AE81FF" }
|
||||
style.syntax["string"] = { common.color "#E6DB74" }
|
||||
style.syntax["operator"] = { common.color "#F8F8F2" }
|
||||
style.syntax["function"] = { common.color "#A6E22E" }
|
|
@ -0,0 +1,28 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#282923" }
|
||||
style.background2 = { common.color "#181915" }
|
||||
style.background3 = { common.color "#181915" }
|
||||
style.text = { common.color "#9ea191" }
|
||||
style.caret = { common.color "#f8f8f2" }
|
||||
style.accent = { common.color "#f8f8f2" }
|
||||
style.dim = { common.color "#5e6052" }
|
||||
style.divider = { common.color "#1b1c17" }
|
||||
style.selection = { common.color "#3a3a32" }
|
||||
style.line_number = { common.color "#90918b" }
|
||||
style.line_number2 = { common.color "#d2d0c6" }
|
||||
style.line_highlight = { common.color "#282923" }
|
||||
style.scrollbar = { common.color "#63635f" }
|
||||
style.scrollbar2 = { common.color "#3d3d38" }
|
||||
|
||||
style.syntax["normal"] = { common.color "#f8f8f2" }
|
||||
style.syntax["symbol"] = { common.color "#f8f8f2" }
|
||||
style.syntax["comment"] = { common.color "#75715E" }
|
||||
style.syntax["keyword"] = { common.color "#f92472" }
|
||||
style.syntax["keyword2"] = { common.color "#f92472" }
|
||||
style.syntax["number"] = { common.color "#ac80ff" }
|
||||
style.syntax["literal"] = { common.color "#e7db74" }
|
||||
style.syntax["string"] = { common.color "#e7db74" }
|
||||
style.syntax["operator"] = { common.color "#f92472" }
|
||||
style.syntax["function"] = { common.color "#5cd5ef" }
|
|
@ -0,0 +1,39 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
local config = require "core.config"
|
||||
|
||||
style.background = { common.color "#2E3440" }
|
||||
style.background2 = { common.color "#2E3440" }
|
||||
style.background3 = { common.color "#3B4252" }
|
||||
style.text = { common.color "#D8DEE9" }
|
||||
style.caret = { common.color "#D8DEE9" }
|
||||
style.accent = { common.color "#88C0D0" }
|
||||
style.dim = { common.color "#d8dee966" }
|
||||
style.divider = { common.color "#3B4252" }
|
||||
style.selection = { common.color "#434C5ECC" }
|
||||
style.line_number = { common.color "#4C566A" }
|
||||
style.line_number2 = { common.color "#D8DEE9" }
|
||||
style.line_highlight = { common.color "#3B4252" }
|
||||
style.scrollbar = { common.color "#434c5eaa" }
|
||||
style.scrollbar2 = { common.color "#434c5e" }
|
||||
style.good = { common.color "#72b886cc" }
|
||||
style.warn = { common.color "#d08770" }
|
||||
style.error = { common.color "#bf616a" }
|
||||
style.modified = { common.color "#ebcb8b" }
|
||||
|
||||
style.syntax["normal"] = { common.color "#ECEFF4" }
|
||||
style.syntax["symbol"] = { common.color "#D8DEE9" }
|
||||
style.syntax["comment"] = { common.color "#616E88" }
|
||||
style.syntax["keyword"] = { common.color "#81A1C1" }
|
||||
style.syntax["keyword2"] = { common.color "#81A1C1" }
|
||||
style.syntax["number"] = { common.color "#B48EAD" }
|
||||
style.syntax["literal"] = { common.color "#81A1C1" }
|
||||
style.syntax["string"] = { common.color "#A3BE8C" }
|
||||
style.syntax["operator"] = { common.color "#81A1C1" }
|
||||
style.syntax["function"] = { common.color "#88C0D0" }
|
||||
|
||||
config.highlight_current_line = "no_selection"
|
||||
|
||||
style.guide = { common.color "#434c5eb3" }
|
||||
style.bracketmatch_color = { common.color "#8fbcbb" }
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#282c34" }
|
||||
style.background2 = { common.color "#21252B" }
|
||||
style.background3 = { common.color "#21252B" }
|
||||
style.text = { common.color "#abb2bf" }
|
||||
style.caret = { common.color "#528bff" }
|
||||
style.accent = { common.color "#ffffff" }
|
||||
style.dim = { common.color "#4f5873" }
|
||||
style.divider = { common.color "#181A1F" }
|
||||
style.selection = { common.color "#383D49" }
|
||||
style.line_number = { common.color "#53576e" }
|
||||
style.line_number2 = { common.color "#666B76" }
|
||||
style.line_highlight = { common.color "#2C333E" }
|
||||
style.scrollbar = { common.color "#4f5873" }
|
||||
style.scrollbar2 = { common.color "#3060C1" }
|
||||
|
||||
style.syntax["normal"] = { common.color "#abb2bf" }
|
||||
style.syntax["symbol"] = { common.color "#abb2bf" }
|
||||
style.syntax["comment"] = { common.color "#5f697a" }
|
||||
style.syntax["keyword"] = { common.color "#cd74e8" }
|
||||
style.syntax["keyword2"] = { common.color "#eb6772" }
|
||||
style.syntax["number"] = { common.color "#db9d63" }
|
||||
style.syntax["literal"] = { common.color "#e6c07b" }
|
||||
style.syntax["string"] = { common.color "#9acc76" }
|
||||
style.syntax["operator"] = { common.color "#56B6C2" }
|
||||
style.syntax["function"] = { common.color "#5cb3fa" }
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#242424" }
|
||||
style.background2 = { common.color "#252528" }
|
||||
style.background3 = { common.color "#44475A" }
|
||||
|
||||
style.text = { common.color "#fffff0" }
|
||||
style.caret = { common.color "#69FF94" }
|
||||
style.accent = { common.color "#ff0fff" }
|
||||
|
||||
style.dim = { common.color "#0fffff" }
|
||||
style.divider = { common.color "#7b7f8b" }
|
||||
style.selection = { common.color "#48484f" }
|
||||
style.selectionhighlight = { common.color "#dddeee" }
|
||||
style.line_number = { common.color "#525259" }
|
||||
style.line_number2 = { common.color "#f6f6e0" }
|
||||
style.line_highlight = { common.color "#343438" }
|
||||
style.scrollbar = { common.color "#414146" }
|
||||
style.scrollbar2 = { common.color "#4b4bff" }
|
||||
|
||||
style.syntax["normal"] = { common.color "#e1e1e6" }
|
||||
style.syntax["symbol"] = { common.color "#97e1f1" }
|
||||
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 "#ee6666" }
|
||||
style.syntax["string"] = { common.color "#f7c95c" }
|
||||
style.syntax["operator"] = { common.color "#93DDFA" }
|
||||
style.syntax["function"] = { common.color "#bf9eee" }
|
|
@ -0,0 +1,29 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#222226" }
|
||||
style.background2 = { common.color "#252528" }
|
||||
style.background3 = { common.color "#1e1e21" }
|
||||
style.text = { common.color "#dddddd" }
|
||||
style.caret = { common.color "#aeafad" }
|
||||
style.accent = { common.color "#0097fb" }
|
||||
style.dim = { common.color "#9393a5" }
|
||||
style.divider = { common.color "#1E1E1E" }
|
||||
style.selection = { common.color "#264f78" }
|
||||
style.line_number = { common.color "#858585" }
|
||||
style.line_number2 = { common.color "#c6c6c6" }
|
||||
style.line_highlight = { common.color "#2b2b2f"}
|
||||
style.scrollbar = { common.color "#313136" }
|
||||
style.scrollbar2 = { common.color "#bfbfbf" }
|
||||
|
||||
style.syntax["normal"] = { common.color "#dddddd" }
|
||||
style.syntax["symbol"] = { common.color "#e06c75" }
|
||||
style.syntax["comment"] = { common.color "#c5c5c5" }
|
||||
style.syntax["keyword"] = { common.color "#61afef" }
|
||||
style.syntax["keyword2"] = { common.color "#56B6C2" }
|
||||
style.syntax["number"] = { common.color "#d19a66" }
|
||||
style.syntax["literal"] = { common.color "#61AFEF" }
|
||||
style.syntax["string"] = { common.color "#98C379" }
|
||||
style.syntax["operator"] = { common.color "#dddddd" }
|
||||
style.syntax["function"] = { common.color "#c678dd" }
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#252336" }
|
||||
style.background2 = { common.color "#171521" }
|
||||
style.background3 = { common.color "#171521" }
|
||||
style.text = { common.color "#8f94bf" }
|
||||
style.caret = { common.color "#f17e6e" }
|
||||
style.accent = { common.color "#ff79c6" }
|
||||
style.dim = { common.color "#4f526b" }
|
||||
style.divider = { common.color "#171521" }
|
||||
style.selection = { common.color "#4a445a" }
|
||||
style.line_number = { common.color "#4a445a" }
|
||||
style.line_number2 = { common.color "#ff79c6" }
|
||||
style.line_highlight = { common.color "rgba(0, 0, 0, 0.30)" }
|
||||
style.scrollbar = { common.color "#4f526b" }
|
||||
style.scrollbar2 = { common.color "#717382" }
|
||||
style.nagbar = { common.color "#ff79c6" }
|
||||
style.nagbar_text = { common.color "#FFFFFF" }
|
||||
style.nagbar_dim = { common.color "rgba(0, 0, 0, 0.30)" }
|
||||
style.drag_overlay = { common.color "rgba(0, 0, 0, 0.30)" }
|
||||
style.drag_overlay_tab = { common.color "#f17e6e" }
|
||||
|
||||
style.syntax["normal"] = { common.color "#FFFFFF" }
|
||||
style.syntax["symbol"] = { common.color "#ff79c6" }
|
||||
style.syntax["comment"] = { common.color "#9484bd" }
|
||||
style.syntax["keyword"] = { common.color "#f5de4a" }
|
||||
style.syntax["keyword2"] = { common.color "#f73f51" }
|
||||
style.syntax["number"] = { common.color "#bd93f9" }
|
||||
style.syntax["literal"] = { common.color "#5afad2" }
|
||||
style.syntax["string"] = { common.color "#ff8b39" }
|
||||
style.syntax["operator"] = { common.color "#f5de4a" }
|
||||
style.syntax["function"] = { common.color "#8be9fd" }
|
||||
|
||||
style.guide = { common.color "#4a445a" }
|
||||
style.bracketmatch_color = { common.color "#f17e6e" }
|
|
@ -0,0 +1,37 @@
|
|||
-- Colors from: https://github.com/enkia/tokyo-night-vscode-theme
|
||||
|
||||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#1a1b26" }
|
||||
style.background2 = { common.color "#16161e" }
|
||||
style.background3 = { common.color "#24283b" }
|
||||
style.text = { common.color "#a9b1d6" }
|
||||
style.caret = { common.color "#a9b1d6" }
|
||||
style.accent = { common.color "#7aa2f7" } -- Text in autocomplete and command, col(>80) in satusbar
|
||||
style.dim = { common.color "#565f89" } -- Text of nonactive tabs, prefix in log
|
||||
style.divider = { common.color "#101014" }
|
||||
style.selection = { common.color "#282B3C" }
|
||||
style.line_number = { common.color "#363B54" }
|
||||
style.line_number2 = { common.color "#737AA2" } -- Number on line with caret
|
||||
style.line_highlight = { common.color "#1E202E"}
|
||||
style.scrollbar = { common.color "#24283b" }
|
||||
style.scrollbar2 = { common.color "#414868" } -- Hovered
|
||||
|
||||
style.syntax["normal"] = { common.color "#9ABDF5" }
|
||||
style.syntax["symbol"] = { common.color "#c0caf5" }
|
||||
style.syntax["comment"] = { common.color "#414868" }
|
||||
style.syntax["keyword"] = { common.color "#bb9af7" } -- local function end, if case
|
||||
style.syntax["keyword2"] = { common.color "#bb9af7" } -- self, int float
|
||||
style.syntax["number"] = { common.color "#ff9e64" }
|
||||
style.syntax["literal"] = { common.color "#c0caf5" }
|
||||
style.syntax["string"] = { common.color "#9ece6a" }
|
||||
style.syntax["operator"] = { common.color "#2ac3de"} -- = + - / < >
|
||||
style.syntax["function"] = { common.color "#7aa2f7" }
|
||||
|
||||
-- PLUGINS
|
||||
style.linter_warning = { common.color "#e0af68" } -- linter
|
||||
style.bracketmatch_color = { common.color "#565f89" } -- bracketmatch
|
||||
style.guide = { common.color "#1E202E" }
|
||||
style.guide_highlight = { common.color "#363B54" } -- indentguide
|
||||
style.guide_width = 1 -- indentguide
|
|
@ -0,0 +1,37 @@
|
|||
-- Most of the colors are taken from:
|
||||
-- https://github.com/microsoft/vscode/tree/master/extensions/theme-defaults/themes
|
||||
|
||||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#1E1E1E" }
|
||||
style.background2 = { common.color "#252526" }
|
||||
style.background3 = { common.color "#252526" }
|
||||
style.text = { common.color "#D4D4D4" }
|
||||
style.caret = { common.color "#FFFFFF" }
|
||||
style.accent = { common.color "#76BCFF" } -- Text in autocomplete and command, col(>80) in satusbar
|
||||
style.dim = { common.color "#7A7A7A" } -- Text of nonactive tabs, prefix in log
|
||||
style.divider = { common.color "#1E1E1E" }
|
||||
style.selection = { common.color "#264F78" }
|
||||
style.line_number = { common.color "#707070" }
|
||||
style.line_number2 = { common.color "#A0A0A0" } -- Number on line with caret
|
||||
style.line_highlight = { common.color "#333A40"}
|
||||
style.scrollbar = { common.color "#404040" }
|
||||
style.scrollbar2 = { common.color "#707070" } -- Hovered
|
||||
|
||||
style.syntax["normal"] = { common.color "#D4D4D4" }
|
||||
style.syntax["symbol"] = { common.color "#D4D4D4" }
|
||||
style.syntax["comment"] = { common.color "#6A9955" }
|
||||
style.syntax["keyword"] = { common.color "#569CD6" } -- local function end, if case
|
||||
style.syntax["keyword2"] = { common.color "#C586C0" } -- self, int float
|
||||
style.syntax["number"] = { common.color "#B5CEA8" }
|
||||
style.syntax["literal"] = { common.color "#569CD6" }
|
||||
style.syntax["string"] = { common.color "#CE9178" }
|
||||
style.syntax["operator"] = { common.color "#8590A5"} -- = + - / < >
|
||||
style.syntax["function"] = { common.color "#DCDCAA" }
|
||||
|
||||
-- PLUGINS
|
||||
style.linter_warning = { common.color "#B89500" } -- linter
|
||||
style.bracketmatch_color = { common.color "#76BCFF" } -- bracketmatch
|
||||
style.guide = { common.color "#404040" } -- indentguide
|
||||
style.guide_width = 1 -- indentguide
|
|
@ -0,0 +1,28 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#282a36" }
|
||||
style.background2 = { common.color "#22242e" }
|
||||
style.background3 = { common.color "#22242e" }
|
||||
style.text = { common.color "#aab3e6" }
|
||||
style.caret = { common.color "#f5faff" }
|
||||
style.accent = { common.color "#ffb86c" }
|
||||
style.dim = { common.color "#4f526b" }
|
||||
style.divider = { common.color "#22242e" }
|
||||
style.selection = { common.color "#4c5163" }
|
||||
style.line_number = { common.color "#44475a" }
|
||||
style.line_number2 = { common.color "#717796" }
|
||||
style.line_highlight = { common.color "#2d303d" }
|
||||
style.scrollbar = { common.color "#44475a" }
|
||||
style.scrollbar2 = { common.color "#4c5163" }
|
||||
|
||||
style.syntax["normal"] = { common.color "#f5faff" }
|
||||
style.syntax["symbol"] = { common.color "#f5faff" }
|
||||
style.syntax["comment"] = { common.color "#6272a4" }
|
||||
style.syntax["keyword"] = { common.color "#ff79c6" }
|
||||
style.syntax["keyword2"] = { common.color "#8be9fd" }
|
||||
style.syntax["number"] = { common.color "#bd93f9" }
|
||||
style.syntax["literal"] = { common.color "#bd93f9" }
|
||||
style.syntax["string"] = { common.color "#f1fa8c" }
|
||||
style.syntax["operator"] = { common.color "#ff79c6" }
|
||||
style.syntax["function"] = { common.color "#8be9fd" }
|
|
@ -0,0 +1,28 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#404040" }
|
||||
style.background2 = { common.color "#3d3d3d" }
|
||||
style.background3 = { common.color "#2b2b2b" }
|
||||
style.text = { common.color "#dcdccc" }
|
||||
style.caret = { common.color "#f8f8f0" }
|
||||
style.accent = { common.color "#dcdccc" }
|
||||
style.dim = { common.color "#8f8f8f" }
|
||||
style.divider = { common.color "#383838" }
|
||||
style.selection = { common.color "#2f2f2f" }
|
||||
style.line_number = { common.color "#545454" }
|
||||
style.line_number2 = { common.color "#545454" }
|
||||
style.line_highlight = { common.color "#383838" }
|
||||
style.scrollbar = { common.color "#4c4c4c" }
|
||||
style.scrollbar2 = { common.color "#5e5e5e" }
|
||||
|
||||
style.syntax["normal"] = { common.color "#dcdccc" }
|
||||
style.syntax["symbol"] = { common.color "#dcdccc" }
|
||||
style.syntax["comment"] = { common.color "#7f9f7f" }
|
||||
style.syntax["keyword"] = { common.color "#f0dfaf" }
|
||||
style.syntax["keyword2"] = { common.color "#dfdfbf" }
|
||||
style.syntax["number"] = { common.color "#8cd0d3" }
|
||||
style.syntax["literal"] = { common.color "#dfaf8f" }
|
||||
style.syntax["string"] = { common.color "#cc9393" }
|
||||
style.syntax["operator"] = { common.color "#f0efd0" }
|
||||
style.syntax["function"] = { common.color "#efef8f" }
|
Binary file not shown.
|
@ -0,0 +1,31 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
-- GitHubs style varies from language to language so its hard to get perfect
|
||||
-- Originally written by thebirk, 2019
|
||||
|
||||
style.background = { common.color "#fbfbfb" }
|
||||
style.background2 = { common.color "#f2f2f2" }
|
||||
style.background3 = { common.color "#f2f2f2" }
|
||||
style.text = { common.color "#404040" }
|
||||
style.caret = { common.color "#181818" }
|
||||
style.accent = { common.color "#0366d6" }
|
||||
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 "#24292e" }
|
||||
style.syntax["symbol"] = { common.color "#24292e" }
|
||||
style.syntax["comment"] = { common.color "#6a737d" }
|
||||
style.syntax["keyword"] = { common.color "#d73a49" }
|
||||
style.syntax["keyword2"] = { common.color "#d73a49" }
|
||||
style.syntax["number"] = { common.color "#005cc5" }
|
||||
style.syntax["literal"] = { common.color "#005cc5" }
|
||||
style.syntax["string"] = { common.color "#032f62" }
|
||||
style.syntax["operator"] = { common.color "#d73a49" }
|
||||
style.syntax["function"] = { common.color "#005cc5" }
|
|
@ -0,0 +1,28 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#fbf1c7" }
|
||||
style.background2 = { common.color "#f9f5d7" }
|
||||
style.background3 = { common.color "#f9f5d7" }
|
||||
style.text = { common.color "#928374" }
|
||||
style.caret = { common.color "#282828" }
|
||||
style.accent = { common.color "#3c3836" }
|
||||
style.dim = { common.color "#928374" }
|
||||
style.divider = { common.color "#f9f5d7" }
|
||||
style.selection = { common.color "#ebdbb2" }
|
||||
style.line_number = { common.color "#928374" }
|
||||
style.line_number2 = { common.color "#3c3836" }
|
||||
style.line_highlight = { common.color "#f2e5bc" }
|
||||
style.scrollbar = { common.color "#928374" }
|
||||
style.scrollbar2 = { common.color "#282828" }
|
||||
|
||||
style.syntax["normal"] = { common.color "#3c3836" }
|
||||
style.syntax["symbol"] = { common.color "#3c3836" }
|
||||
style.syntax["comment"] = { common.color "#928374" }
|
||||
style.syntax["keyword"] = { common.color "#9d0006" }
|
||||
style.syntax["keyword2"] = { common.color "#076678" }
|
||||
style.syntax["number"] = { common.color "#8f3f71" }
|
||||
style.syntax["literal"] = { common.color "#8f3f71" }
|
||||
style.syntax["string"] = { common.color "#79740e" }
|
||||
style.syntax["operator"] = { common.color "#3c3836" }
|
||||
style.syntax["function"] = { common.color "#427b58" }
|
|
@ -0,0 +1,28 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#f7f9f9" }
|
||||
style.background2 = { common.color "#f7f9f9" }
|
||||
style.background3 = { common.color "#f7f9f9" }
|
||||
style.text = { common.color "#404040" }
|
||||
style.caret = { common.color "#ff5971" }
|
||||
style.accent = { common.color "#ff5971" }
|
||||
style.dim = { common.color "#b0b0b0" }
|
||||
style.divider = { common.color "#e8e8e8" }
|
||||
style.selection = { common.color "#fde6eb" }
|
||||
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 "#43cdbd" }
|
||||
style.syntax["keyword"] = { common.color "#5f7dcd" }
|
||||
style.syntax["keyword2"] = { common.color "#9c53c6" }
|
||||
style.syntax["number"] = { common.color "#3daee9" }
|
||||
style.syntax["literal"] = { common.color "#3daee9" }
|
||||
style.syntax["string"] = { common.color "#3daee9" }
|
||||
style.syntax["operator"] = { common.color "#5f7dcd" }
|
||||
style.syntax["function"] = { common.color "#9c53c6" }
|
|
@ -0,0 +1,28 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#fdf6e3" }
|
||||
style.background2 = { common.color "#eee8d5" }
|
||||
style.background3 = { common.color "#eee8d5" }
|
||||
style.text = { common.color "#657b83" }
|
||||
style.caret = { common.color "#657b83" }
|
||||
style.accent = { common.color "#002b36" }
|
||||
style.dim = { common.color "#93a1a1" }
|
||||
style.divider = { common.color "#e0dbc8" }
|
||||
style.selection = { common.color "#073642" }
|
||||
style.line_number = { common.color "#93a1a1" }
|
||||
style.line_number2 = { common.color "#002b36" }
|
||||
style.line_highlight = { common.color "#eee8d5" }
|
||||
style.scrollbar = { common.color "#e0dbc8" }
|
||||
style.scrollbar2 = { common.color "#bfbbaa" }
|
||||
|
||||
style.syntax["normal"] = { common.color "#657b83" }
|
||||
style.syntax["symbol"] = { common.color "#657b83" }
|
||||
style.syntax["comment"] = { common.color "#93a1a1" }
|
||||
style.syntax["keyword"] = { common.color "#859900" }
|
||||
style.syntax["keyword2"] = { common.color "#268bd2" }
|
||||
style.syntax["number"] = { common.color "#d33682" }
|
||||
style.syntax["literal"] = { common.color "#2aa198" }
|
||||
style.syntax["string"] = { common.color "#2aa198" }
|
||||
style.syntax["operator"] = { common.color "#859900" }
|
||||
style.syntax["function"] = { common.color "#268bd2" }
|
|
@ -0,0 +1,28 @@
|
|||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
|
||||
style.background = { common.color "#fdf6e3" }
|
||||
style.background2 = { common.color "#2e2c29" }
|
||||
style.background3 = { common.color "#3e3c37" }
|
||||
style.text = { common.color "#b2ada1" }
|
||||
style.caret = { common.color "#b2ada1" }
|
||||
style.accent = { common.color "#6c71c4" }
|
||||
style.dim = { common.color "#b2ada1" }
|
||||
style.divider = { common.color "#201f1d" }
|
||||
style.selection = { common.color "#eee8d5" }
|
||||
style.line_number = { common.color "#93a1a1" }
|
||||
style.line_number2 = { common.color "#002b36" }
|
||||
style.line_highlight = { common.color "#fcefcd" }
|
||||
style.scrollbar = { common.color "#e0dbc8" }
|
||||
style.scrollbar2 = { common.color "#9d9988" }
|
||||
|
||||
style.syntax["normal"] = { common.color "#3e3c37" }
|
||||
style.syntax["symbol"] = { common.color "#4c4f82" }
|
||||
style.syntax["comment"] = { common.color "#93a1a1" }
|
||||
style.syntax["keyword"] = { common.color "#d33682" }
|
||||
style.syntax["keyword2"] = { common.color "#6c71c4" }
|
||||
style.syntax["number"] = { common.color "#859900" }
|
||||
style.syntax["literal"] = { common.color "#b58900" }
|
||||
style.syntax["string"] = { common.color "#cb4b16" }
|
||||
style.syntax["operator"] = { common.color "#859900" }
|
||||
style.syntax["function"] = { common.color "#268bd2" }
|
Binary file not shown.
|
@ -0,0 +1,129 @@
|
|||
-- mod-version:3
|
||||
local core = require "core"
|
||||
local translate = require "core.doc.translate"
|
||||
local config = require "core.config"
|
||||
local common = require "core.common"
|
||||
local DocView = require "core.docview"
|
||||
local command = require "core.command"
|
||||
local keymap = require "core.keymap"
|
||||
|
||||
|
||||
config.plugins.autoinsert = common.merge({ map = {
|
||||
["["] = "]",
|
||||
["{"] = "}",
|
||||
["("] = ")",
|
||||
['"'] = '"',
|
||||
["'"] = "'",
|
||||
["`"] = "`",
|
||||
} }, config.plugins.autoinsert)
|
||||
|
||||
|
||||
-- Workaround for bug in Lite XL 2.1
|
||||
-- Remove this when b029f5993edb7dee5ccd2ba55faac1ec22e24609 is in a release
|
||||
local function get_selection(doc, sort)
|
||||
local line1, col1, line2, col2 = doc:get_selection_idx(doc.last_selection)
|
||||
if line1 then
|
||||
return doc:get_selection_idx(doc.last_selection, sort)
|
||||
else
|
||||
return doc:get_selection_idx(1, sort)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function is_closer(chr)
|
||||
for _, v in pairs(config.plugins.autoinsert.map) do
|
||||
if v == chr then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function count_char(text, chr)
|
||||
local count = 0
|
||||
for _ in text:gmatch(chr) do
|
||||
count = count + 1
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
|
||||
local on_text_input = DocView.on_text_input
|
||||
|
||||
function DocView:on_text_input(text)
|
||||
local mapping = config.plugins.autoinsert.map[text]
|
||||
|
||||
-- prevents plugin from operating on `CommandView`
|
||||
if getmetatable(self) ~= DocView then
|
||||
return on_text_input(self, text)
|
||||
end
|
||||
|
||||
-- wrap selection if we have a selection
|
||||
if mapping and self.doc:has_selection() then
|
||||
local l1, c1, l2, c2, swap = get_selection(self.doc, true)
|
||||
self.doc:insert(l2, c2, mapping)
|
||||
self.doc:insert(l1, c1, text)
|
||||
self.doc:set_selection(l1, c1, l2, c2 + 2, swap)
|
||||
return
|
||||
end
|
||||
|
||||
-- skip inserting closing text
|
||||
local chr = self.doc:get_char(self.doc:get_selection())
|
||||
if text == chr and is_closer(chr) then
|
||||
self.doc:move_to(1)
|
||||
return
|
||||
end
|
||||
|
||||
-- don't insert closing quote if we have a non-even number on this line
|
||||
local line = self.doc:get_selection()
|
||||
if text == mapping and count_char(self.doc.lines[line], text) % 2 == 1 then
|
||||
return on_text_input(self, text)
|
||||
end
|
||||
|
||||
-- auto insert closing bracket
|
||||
if mapping and (chr:find("%s") or is_closer(chr) and chr ~= '"') then
|
||||
on_text_input(self, text)
|
||||
on_text_input(self, mapping)
|
||||
self.doc:move_to(-1)
|
||||
return
|
||||
end
|
||||
|
||||
on_text_input(self, text)
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function predicate()
|
||||
return core.active_view:is(DocView)
|
||||
and not core.active_view.doc:has_selection(), core.active_view.doc
|
||||
end
|
||||
|
||||
command.add(predicate, {
|
||||
["autoinsert:backspace"] = function(doc)
|
||||
local l, c = doc:get_selection()
|
||||
if c > 1 then
|
||||
local chr = doc:get_char(l, c)
|
||||
local mapped = config.plugins.autoinsert.map[doc:get_char(l, c - 1)]
|
||||
if mapped and mapped == chr then
|
||||
doc:delete_to(1)
|
||||
end
|
||||
end
|
||||
command.perform "doc:backspace"
|
||||
end,
|
||||
|
||||
["autoinsert:delete-to-previous-word-start"] = function(doc)
|
||||
local le, ce = translate.previous_word_start(doc, doc:get_selection())
|
||||
while true do
|
||||
local l, c = doc:get_selection()
|
||||
if l == le and c == ce then
|
||||
break
|
||||
end
|
||||
command.perform "autoinsert:backspace"
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
keymap.add {
|
||||
["backspace"] = "autoinsert:backspace",
|
||||
["ctrl+backspace"] = "autoinsert:delete-to-previous-word-start",
|
||||
["ctrl+shift+backspace"] = "autoinsert:delete-to-previous-word-start",
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
-- mod-version:3
|
||||
local core = require "core"
|
||||
local config = require "core.config"
|
||||
local command = require "core.command"
|
||||
local common = require "core.common"
|
||||
local DocView = require "core.docview"
|
||||
|
||||
config.plugins.autowrap = common.merge({
|
||||
enabled = false,
|
||||
files = { "%.md$", "%.txt$" },
|
||||
-- The config specification used by the settings gui
|
||||
config_spec = {
|
||||
name = "Auto Wrap",
|
||||
{
|
||||
label = "Enable",
|
||||
description = "Activates text auto wrapping by default.",
|
||||
path = "enabled",
|
||||
type = "toggle",
|
||||
default = false
|
||||
},
|
||||
{
|
||||
label = "Files",
|
||||
description = "List of Lua patterns matching files to auto wrap.",
|
||||
path = "files",
|
||||
type = "list_strings",
|
||||
default = { "%.md$", "%.txt$" },
|
||||
}
|
||||
}
|
||||
}, config.plugins.autowrap)
|
||||
|
||||
|
||||
local on_text_input = DocView.on_text_input
|
||||
|
||||
DocView.on_text_input = function(self, ...)
|
||||
on_text_input(self, ...)
|
||||
|
||||
if not config.plugins.autowrap.enabled then return end
|
||||
|
||||
-- early-exit if the filename does not match a file type pattern
|
||||
local filename = self.doc.filename or ""
|
||||
local matched = false
|
||||
for _, ptn in ipairs(config.plugins.autowrap.files) do
|
||||
if filename:match(ptn) then
|
||||
matched = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not matched then return end
|
||||
|
||||
-- do automatic reflow on line if we're typing at the end of the line and have
|
||||
-- reached the line limit
|
||||
local line, col = self.doc:get_selection()
|
||||
local text = self.doc:get_text(line, 1, line, math.huge)
|
||||
if #text >= config.line_limit and col > #text then
|
||||
command.perform("doc:select-lines")
|
||||
command.perform("reflow:reflow")
|
||||
command.perform("doc:move-to-next-char")
|
||||
command.perform("doc:move-to-end-of-line")
|
||||
end
|
||||
end
|
||||
|
||||
command.add(nil, {
|
||||
["auto-wrap:toggle"] = function()
|
||||
config.plugins.autowrap.enabled = not config.plugins.autowrap.enabled
|
||||
if config.plugins.autowrap.enabled then
|
||||
core.log("Auto wrap: on")
|
||||
else
|
||||
core.log("Auto wrap: off")
|
||||
end
|
||||
end
|
||||
})
|
|
@ -0,0 +1,108 @@
|
|||
-- mod-version:3
|
||||
local core = require "core"
|
||||
local style = require "core.style"
|
||||
local command = require "core.command"
|
||||
local common = require "core.common"
|
||||
local config = require "core.config"
|
||||
local View = require "core.view"
|
||||
|
||||
|
||||
config.plugins.bigclock = common.merge({
|
||||
time_format = "%H:%M:%S",
|
||||
date_format = "%A, %d %B %Y",
|
||||
scale = 1,
|
||||
-- The config specification used by the settings gui
|
||||
config_spec = {
|
||||
name = "Big Clock",
|
||||
{
|
||||
label = "Time Format",
|
||||
description = "Time specification defined with Lua date/time place holders.",
|
||||
path = "time_format",
|
||||
type = "string",
|
||||
default = "%H:%M:%S"
|
||||
},
|
||||
{
|
||||
label = "Date Format",
|
||||
description = "Date specification defined with Lua date/time place holders.",
|
||||
path = "date_format",
|
||||
type = "string",
|
||||
default = "%A, %d %B %Y",
|
||||
},
|
||||
{
|
||||
label = "Scale",
|
||||
description = "Size of the clock relative to screen.",
|
||||
path = "scale",
|
||||
type = "number",
|
||||
default = 1,
|
||||
min = 0.5,
|
||||
max = 3.0,
|
||||
step = 0.1
|
||||
}
|
||||
}
|
||||
}, config.plugins.bigclock)
|
||||
|
||||
|
||||
local ClockView = View:extend()
|
||||
|
||||
|
||||
function ClockView:new()
|
||||
ClockView.super.new(self)
|
||||
self.time_text = ""
|
||||
self.date_text = ""
|
||||
self.last_scale = 0
|
||||
end
|
||||
|
||||
|
||||
function ClockView:get_name()
|
||||
return "Big Clock"
|
||||
end
|
||||
|
||||
|
||||
function ClockView:update_fonts()
|
||||
if self.last_scale ~= config.plugins.bigclock.scale then
|
||||
self.last_scale = config.plugins.bigclock.scale
|
||||
else
|
||||
return
|
||||
end
|
||||
local size = math.floor(self.size.x * 0.15 / 15) * 15 * config.plugins.bigclock.scale
|
||||
if self.font_size ~= size then
|
||||
self.time_font = renderer.font.copy(style["font"], size)
|
||||
self.date_font = renderer.font.copy(style["font"], size * 0.3)
|
||||
self.font_size = size
|
||||
collectgarbage()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function ClockView:update()
|
||||
local time_text = os.date(config.plugins.bigclock.time_format)
|
||||
local date_text = os.date(config.plugins.bigclock.date_format)
|
||||
if self.time_text ~= time_text or self.date_text ~= date_text then
|
||||
core.redraw = true
|
||||
self.time_text = time_text
|
||||
self.date_text = date_text
|
||||
end
|
||||
ClockView.super.update(self)
|
||||
end
|
||||
|
||||
|
||||
function ClockView:draw()
|
||||
self:update_fonts()
|
||||
self:draw_background(style.background)
|
||||
local x, y = self.position.x, self.position.y
|
||||
local w, h = self.size.x, self.size.y
|
||||
local _, y = common.draw_text(self.time_font, style.text, self.time_text, "center", x, y, w, h)
|
||||
local th = self.date_font:get_height()
|
||||
common.draw_text(self.date_font, style.dim, self.date_text, "center", x, y, w, th)
|
||||
end
|
||||
|
||||
|
||||
command.add(nil, {
|
||||
["big-clock:open"] = function()
|
||||
local node = core.root_view:get_active_node()
|
||||
node:add_view(ClockView())
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
return ClockView
|
|
@ -0,0 +1,265 @@
|
|||
--- mod-version:3
|
||||
local core = require "core"
|
||||
local style = require "core.style"
|
||||
local command = require "core.command"
|
||||
local keymap = require "core.keymap"
|
||||
local DocView = require "core.docview"
|
||||
local config = require "core.config"
|
||||
local common = require "core.common"
|
||||
|
||||
-- Colors can be configured as follows:
|
||||
-- underline color = `style.bracketmatch_color`
|
||||
-- bracket color = `style.bracketmatch_char_color`
|
||||
-- background color = `style.bracketmatch_block_color`
|
||||
-- frame color = `style.bracketmatch_frame_color`
|
||||
|
||||
config.plugins.bracketmatch = common.merge({
|
||||
-- highlight the current bracket too
|
||||
highlight_both = true,
|
||||
-- can be "underline", "block", "frame", "none"
|
||||
style = "underline",
|
||||
-- color the bracket
|
||||
color_char = false,
|
||||
-- the size of the lines used in "underline" and "frame"
|
||||
line_size = math.ceil(1 * SCALE),
|
||||
-- The config specification used by the settings gui
|
||||
config_spec = {
|
||||
name = "Bracket Match",
|
||||
{
|
||||
label = "Highlight Both",
|
||||
description = "Highlight the current bracket too.",
|
||||
path = "highlight_both",
|
||||
type = "toggle",
|
||||
default = true
|
||||
},
|
||||
{
|
||||
label = "Style",
|
||||
description = "The visual indicator for pair brackets.",
|
||||
path = "style",
|
||||
type = "selection",
|
||||
default = "underline",
|
||||
values = {
|
||||
{"Underline", "underline"},
|
||||
{"Block", "block"},
|
||||
{"Frame", "frame"},
|
||||
{"None", "none"}
|
||||
}
|
||||
},
|
||||
{
|
||||
label = "Colorize Bracket",
|
||||
description = "Change the color of the matching brackets.",
|
||||
path = "color_char",
|
||||
type = "toggle",
|
||||
default = false
|
||||
},
|
||||
{
|
||||
label = "Line Size",
|
||||
description = "Height of the underline on matching brackets.",
|
||||
path = "line_size",
|
||||
type = "number",
|
||||
default = 1,
|
||||
min = 1,
|
||||
step = 1,
|
||||
get_value = function(value)
|
||||
return math.floor(value / SCALE)
|
||||
end,
|
||||
set_value = function(value)
|
||||
return math.ceil(value * SCALE)
|
||||
end
|
||||
}
|
||||
}
|
||||
}, config.plugins.bracketmatch)
|
||||
|
||||
|
||||
local bracket_maps = {
|
||||
-- [ ] ( ) { }
|
||||
{ [91] = 93, [40] = 41, [123] = 125, direction = 1 },
|
||||
-- ] [ ) ( } {
|
||||
{ [93] = 91, [41] = 40, [125] = 123, direction = -1 },
|
||||
}
|
||||
|
||||
|
||||
local function get_token_at(doc, line, col)
|
||||
local column = 0
|
||||
for _,type,text in doc.highlighter:each_token(line) do
|
||||
column = column + #text
|
||||
if column >= col then return type, text end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function get_matching_bracket(doc, line, col, line_limit, open_byte, close_byte, direction)
|
||||
local end_line = line + line_limit * direction
|
||||
local depth = 0
|
||||
|
||||
while line ~= end_line do
|
||||
local byte = doc.lines[line]:byte(col)
|
||||
if byte == open_byte and get_token_at(doc, line, col) ~= "comment" then
|
||||
depth = depth + 1
|
||||
elseif byte == close_byte and get_token_at(doc, line, col) ~= "comment" then
|
||||
depth = depth - 1
|
||||
if depth == 0 then return line, col end
|
||||
end
|
||||
|
||||
local prev_line, prev_col = line, col
|
||||
line, col = doc:position_offset(line, col, direction)
|
||||
if line == prev_line and col == prev_col then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local state = {}
|
||||
local select_adj = 0
|
||||
|
||||
local function update_state(line_limit)
|
||||
line_limit = line_limit or math.huge
|
||||
|
||||
-- reset if we don't have a document (eg. DocView isn't focused)
|
||||
local doc = core.active_view.doc
|
||||
if not doc then
|
||||
state = {}
|
||||
return
|
||||
end
|
||||
|
||||
-- early exit if nothing has changed since the last call
|
||||
local line, col = doc:get_selection()
|
||||
local change_id = doc:get_change_id()
|
||||
if state.doc == doc and state.line == line and state.col == col
|
||||
and state.change_id == change_id and state.limit == line_limit then
|
||||
return
|
||||
end
|
||||
|
||||
-- find matching bracket if we're on a bracket
|
||||
local line2, col2
|
||||
for _, map in ipairs(bracket_maps) do
|
||||
for i = 0, -1, -1 do
|
||||
local line, col = doc:position_offset(line, col, i)
|
||||
local open = doc.lines[line]:byte(col)
|
||||
local close = map[open]
|
||||
if close and get_token_at(doc, line, col) ~= "comment" then
|
||||
-- i == 0 if the cursor is on the left side of a bracket (or -1 when on right)
|
||||
select_adj = i + 1 -- if i == 0 then select_adj = 1 else select_adj = 0 end
|
||||
line2, col2 = get_matching_bracket(doc, line, col, line_limit, open, close, map.direction)
|
||||
goto found
|
||||
end
|
||||
end
|
||||
end
|
||||
::found::
|
||||
|
||||
-- update
|
||||
state = {
|
||||
change_id = change_id,
|
||||
doc = doc,
|
||||
line = line,
|
||||
col = col,
|
||||
line2 = line2,
|
||||
col2 = col2,
|
||||
limit = line_limit,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
local update = DocView.update
|
||||
|
||||
function DocView:update(...)
|
||||
update(self, ...)
|
||||
update_state(100)
|
||||
end
|
||||
|
||||
|
||||
local function redraw_char(dv, x, y, line, col, bg_color, char_color)
|
||||
local x1 = x + dv:get_col_x_offset(line, col)
|
||||
local x2 = x + dv:get_col_x_offset(line, col + 1)
|
||||
local lh = dv:get_line_height()
|
||||
local token = get_token_at(dv.doc, line, col)
|
||||
if not char_color then
|
||||
char_color = style.syntax[token]
|
||||
end
|
||||
local font = style.syntax_fonts[token] or dv:get_font()
|
||||
local char = string.sub(dv.doc.lines[line], col, col)
|
||||
|
||||
if not bg_color then
|
||||
-- redraw background
|
||||
core.push_clip_rect(x1, y, x2 - x1, lh)
|
||||
local dlt = DocView.draw_line_text
|
||||
DocView.draw_line_text = function() end
|
||||
dv:draw_line_body(line, x, y)
|
||||
DocView.draw_line_text = dlt
|
||||
core.pop_clip_rect()
|
||||
else
|
||||
renderer.draw_rect(x1, y, x2 - x1, lh, bg_color)
|
||||
end
|
||||
renderer.draw_text(font, char, x1, y + dv:get_line_text_y_offset(), char_color)
|
||||
end
|
||||
|
||||
|
||||
local function draw_decoration(dv, x, y, line, col)
|
||||
local conf = config.plugins.bracketmatch
|
||||
local color = style.bracketmatch_color or style.syntax["function"]
|
||||
local char_color = style.bracketmatch_char_color
|
||||
or (conf.style == "block" and style.background or style.syntax["keyword"])
|
||||
local block_color = style.bracketmatch_block_color or style.line_number2
|
||||
local frame_color = style.bracketmatch_frame_color or style.line_number2
|
||||
|
||||
local h = conf.line_size
|
||||
|
||||
if conf.color_char or conf.style == "block" then
|
||||
redraw_char(dv, x, y, line, col,
|
||||
conf.style == "block" and block_color, conf.color_char and char_color)
|
||||
end
|
||||
if conf.style == "underline" then
|
||||
local x1 = x + dv:get_col_x_offset(line, col)
|
||||
local x2 = x + dv:get_col_x_offset(line, col + 1)
|
||||
local lh = dv:get_line_height()
|
||||
|
||||
renderer.draw_rect(x1, y + lh - h, x2 - x1, h, color)
|
||||
elseif conf.style == "frame" then
|
||||
local x1 = x + dv:get_col_x_offset(line, col)
|
||||
local x2 = x + dv:get_col_x_offset(line, col + 1)
|
||||
local lh = dv:get_line_height()
|
||||
|
||||
renderer.draw_rect(x1, y + lh - h, x2 - x1, h, frame_color)
|
||||
renderer.draw_rect(x1, y, x2 - x1, h, frame_color)
|
||||
renderer.draw_rect(x1, y, h, lh, frame_color)
|
||||
renderer.draw_rect(x2, y, h, lh, frame_color)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local draw_line_text = DocView.draw_line_text
|
||||
|
||||
function DocView:draw_line_text(line, x, y)
|
||||
local lh = draw_line_text(self, line, x, y)
|
||||
if self.doc == state.doc and state.line2 then
|
||||
if line == state.line2 then
|
||||
draw_decoration(self, x, y, line, state.col2)
|
||||
end
|
||||
if line == state.line and config.plugins.bracketmatch.highlight_both then
|
||||
draw_decoration(self, x, y, line, state.col + select_adj - 1)
|
||||
end
|
||||
end
|
||||
return lh
|
||||
end
|
||||
|
||||
|
||||
command.add("core.docview", {
|
||||
["bracket-match:move-to-matching"] = function(dv)
|
||||
update_state()
|
||||
if state.line2 then
|
||||
dv.doc:set_selection(state.line2, state.col2)
|
||||
end
|
||||
end,
|
||||
["bracket-match:select-to-matching"] = function(dv)
|
||||
update_state()
|
||||
if state.line2 then
|
||||
dv.doc:set_selection(state.line, state.col, state.line2, state.col2 + select_adj)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
keymap.add {
|
||||
["ctrl+m"] = "bracket-match:move-to-matching",
|
||||
["ctrl+shift+m"] = "bracket-match:select-to-matching",
|
||||
}
|
|
@ -0,0 +1,370 @@
|
|||
--mod-version:3 --priority:5
|
||||
|
||||
--[[
|
||||
This code is responsible for the encoding change
|
||||
using codesets library. It requires LiteXL 2.1.1r3
|
||||
and above to work.
|
||||
|
||||
Heavily inspired from the encoding plugin
|
||||
https://github.com/jgmdev/lite-xl-encoding
|
||||
|
||||
Configuration:
|
||||
useSystemEncoding
|
||||
By default the system encoding is used to open
|
||||
a file. If you want to disable that you may add
|
||||
the following line in you config file
|
||||
config.plugins.codesets.useSystemEncoding = false
|
||||
]]
|
||||
|
||||
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 Doc = require "core.doc"
|
||||
local DocView = require "core.docview"
|
||||
local CommandView = require "core.commandview"
|
||||
local StatusView = require "core.statusview"
|
||||
|
||||
---@type encoding
|
||||
local encoding = require "codesetsextra"
|
||||
config.plugins.codesets = common.merge({
|
||||
useSystemEncoding = true
|
||||
}, config.plugins.codesets)
|
||||
|
||||
-- Reference to plugin config
|
||||
local conf = config.plugins.codesets
|
||||
|
||||
local encodings = {}
|
||||
|
||||
---@class encodings.encoding
|
||||
---@field charset string
|
||||
---@field name string
|
||||
|
||||
---List of encoding regions.
|
||||
---@type table<integer,string>
|
||||
encodings.groups = {
|
||||
"West European",
|
||||
"East European",
|
||||
"East Asian",
|
||||
"SE & SW Asian",
|
||||
"Middle Eastern",
|
||||
"Unicode"
|
||||
}
|
||||
|
||||
---Supported iconv encodings grouped by region.
|
||||
---@type table<integer,encodings.encoding[]>
|
||||
encodings.list = {
|
||||
-- West European
|
||||
{
|
||||
{ charset = "ISO-8859-14", name = "Celtic" },
|
||||
{ charset = "ISO-8859-7", name = "Greek" },
|
||||
{ charset = "WINDOWS-1253", name = "Greek" },
|
||||
{ charset = "ISO-8859-10", name = "Nordic" },
|
||||
{ charset = "ISO-8859-3", name = "South European" },
|
||||
{ charset = "IBM850", name = "Western" },
|
||||
{ charset = "ISO-8859-1", name = "Western" },
|
||||
{ charset = "ISO-8859-15", name = "Western" },
|
||||
{ charset = "WINDOWS-1252", name = "Western" }
|
||||
},
|
||||
-- East European
|
||||
{
|
||||
{ charset = "ISO-8859-4", name = "Baltic" },
|
||||
{ charset = "ISO-8859-13", name = "Baltic" },
|
||||
{ charset = "WINDOWS-1257", name = "Baltic" },
|
||||
{ charset = "IBM852", name = "Central European" },
|
||||
{ charset = "ISO-8859-2", name = "Central European" },
|
||||
{ charset = "WINDOWS-1250", name = "Central European" },
|
||||
{ charset = "IBM855", name = "Cyrillic" },
|
||||
{ charset = "ISO-8859-5", name = "Cyrillic" },
|
||||
{ charset = "ISO-IR-111", name = "Cyrillic" },
|
||||
{ charset = "KOI8-R", name = "Cyrillic" },
|
||||
{ charset = "WINDOWS-1251", name = "Cyrillic" },
|
||||
{ charset = "CP866", name = "Cyrillic/Russian" },
|
||||
{ charset = "KOI8-U", name = "Cyrillic/Ukrainian" },
|
||||
{ charset = "ISO-8859-16", name = "Romanian" }
|
||||
},
|
||||
-- East Asian
|
||||
{
|
||||
{ charset = "GB18030", name = "Chinese Simplified" },
|
||||
{ charset = "GB2312", name = "Chinese Simplified" },
|
||||
{ charset = "GBK", name = "Chinese Simplified" },
|
||||
{ charset = "HZ", name = "Chinese Simplified" },
|
||||
{ charset = "BIG5", name = "Chinese Traditional" },
|
||||
{ charset = "BIG5-HKSCS", name = "Chinese Traditional" },
|
||||
{ charset = "EUC-TW", name = "Chinese Traditional" },
|
||||
{ charset = "EUC-JP", name = "Japanese" },
|
||||
{ charset = "ISO-2022-JP", name = "Japanese" },
|
||||
{ charset = "SHIFT_JIS", name = "Japanese" },
|
||||
{ charset = "CP932", name = "Japanese" },
|
||||
{ charset = "EUC-KR", name = "Korean" },
|
||||
{ charset = "ISO-2022-KR", name = "Korean" },
|
||||
{ charset = "JOHAB", name = "Korean" },
|
||||
{ charset = "UHC", name = "Korean" }
|
||||
},
|
||||
-- SE & SW Asian
|
||||
{
|
||||
{ charset = "ARMSCII-8", name = "Armenian" },
|
||||
{ charset = "GEORGIAN-ACADEMY", name = "Georgian" },
|
||||
{ charset = "TIS-620", name = "Thai" },
|
||||
{ charset = "IBM857", name = "Turkish" },
|
||||
{ charset = "WINDOWS-1254", name = "Turkish" },
|
||||
{ charset = "ISO-8859-9", name = "Turkish" },
|
||||
{ charset = "TCVN", name = "Vietnamese" },
|
||||
{ charset = "VISCII", name = "Vietnamese" },
|
||||
{ charset = "WINDOWS-1258", name = "Vietnamese" }
|
||||
},
|
||||
-- Middle Eastern
|
||||
{
|
||||
{ charset = "IBM864", name = "Arabic" },
|
||||
{ charset = "ISO-8859-6", name = "Arabic" },
|
||||
{ charset = "WINDOWS-1256", name = "Arabic" },
|
||||
{ charset = "IBM862", name = "Hebrew" },
|
||||
{ charset = "ISO-8859-8-I", name = "Hebrew" },
|
||||
{ charset = "WINDOWS-1255", name = "Hebrew" },
|
||||
{ charset = "ISO-8859-8", name = "Hebrew Visual" }
|
||||
},
|
||||
-- Unicode
|
||||
{
|
||||
{ charset = "UTF-7", name = "Unicode" },
|
||||
{ charset = "UTF-8", name = "Unicode" },
|
||||
{ charset = "UTF-16LE", name = "Unicode" },
|
||||
{ charset = "UTF-16BE", name = "Unicode" },
|
||||
{ charset = "UCS-2LE", name = "Unicode" },
|
||||
{ charset = "UCS-2BE", name = "Unicode" },
|
||||
{ charset = "UTF-32LE", name = "Unicode" },
|
||||
{ charset = "UTF-32BE", name = "Unicode" }
|
||||
}
|
||||
};
|
||||
|
||||
---Get the list of encodings associated to a region.
|
||||
---@param label string
|
||||
---@return encodings.encoding[] | nil
|
||||
function encodings.get_group(label)
|
||||
for idx, name in ipairs(encodings.groups) do
|
||||
if name == label then
|
||||
return encodings.list[idx]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---Get the list of encodings associated to a region.
|
||||
---@return encodings.encoding[] | nil
|
||||
function encodings.get_all()
|
||||
local all = {}
|
||||
for idx, _ in ipairs(encodings.groups) do
|
||||
for _, item in ipairs(encodings.list[idx]) do
|
||||
table.insert(all, item)
|
||||
end
|
||||
end
|
||||
return all
|
||||
end
|
||||
|
||||
---Open a commandview to select a charset and executes the given callback,
|
||||
---@param title_label string Title displayed on the commandview
|
||||
---@param callback fun(charset: string)
|
||||
function encodings.select_encoding(title_label, callback)
|
||||
core.command_view:enter(title_label, {
|
||||
submit = function(_, item)
|
||||
callback(item.charset)
|
||||
end,
|
||||
suggest = function(text)
|
||||
local charsets = encodings.get_all()
|
||||
local list_labels = {}
|
||||
local list_charset = {}
|
||||
for _, element in ipairs(charsets) do
|
||||
local label = element.name .. " (" .. element.charset .. ")"
|
||||
table.insert(list_labels, label)
|
||||
list_charset[label] = element.charset
|
||||
end
|
||||
local res = common.fuzzy_match(list_labels, text)
|
||||
for i, name in ipairs(res) do
|
||||
res[i] = {
|
||||
text = name,
|
||||
charset = list_charset[name]
|
||||
}
|
||||
end
|
||||
return res
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Overwrite Doc methods to properly add encoding detection and conversion.
|
||||
--------------------------------------------------------------------------------
|
||||
function Doc:new(filename, abs_filename, new_file)
|
||||
self.new_file = new_file
|
||||
self.encoding = nil
|
||||
self.convert = false
|
||||
self:reset()
|
||||
if filename then
|
||||
self:set_filename(filename, abs_filename)
|
||||
if not new_file then
|
||||
self:load(filename)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Doc:load(filename)
|
||||
if not self.encoding then
|
||||
local errmsg
|
||||
if conf.useSystemEncoding then
|
||||
self.encoding, errmsg = encoding.systemCodeset();
|
||||
else
|
||||
self.encoding, errmsg = encoding.detect(filename);
|
||||
end
|
||||
if not self.encoding then core.error("%s", errmsg) error(errmsg) end
|
||||
end
|
||||
self.convert = false
|
||||
if self.encoding ~= "UTF-8" and self.encoding ~= "ASCII"
|
||||
and self.encoding ~= "US-ASCII" and self.encoding ~= "ISO-8859-1"
|
||||
then
|
||||
self.convert = true
|
||||
end
|
||||
local fp = assert( io.open(filename, "rb") )
|
||||
self:reset()
|
||||
self.lines = {}
|
||||
local i = 1
|
||||
if self.convert then
|
||||
local content = fp:read("*a");
|
||||
content = assert(encoding.convert("UTF-8", self.encoding, content, {
|
||||
strict = false,
|
||||
handle_from_bom = true
|
||||
}))
|
||||
for line in content:gmatch("([^\n]*)\n?") do
|
||||
if line:byte(-1) == 13 then
|
||||
line = line:sub(1, -2)
|
||||
self.crlf = true
|
||||
end
|
||||
table.insert(self.lines, line .. "\n")
|
||||
self.highlighter.lines[i] = false
|
||||
i = i + 1
|
||||
end
|
||||
content = nil
|
||||
else
|
||||
for line in fp:lines() do
|
||||
if (i == 1) then line = encoding.strip_bom(line, "UTF-8") end
|
||||
if line:byte(-1) == 13 then
|
||||
line = line:sub(1, -2)
|
||||
self.crlf = true
|
||||
end
|
||||
table.insert(self.lines, line .. "\n")
|
||||
self.highlighter.lines[i] = false
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
if #self.lines == 0 then
|
||||
table.insert(self.lines, "\n")
|
||||
end
|
||||
fp:close()
|
||||
self:reset_syntax()
|
||||
end
|
||||
|
||||
function Doc:save(filename, abs_filename)
|
||||
if not filename then
|
||||
assert(self.filename, "no filename set to default to")
|
||||
filename = self.filename
|
||||
abs_filename = self.abs_filename
|
||||
else
|
||||
assert(self.filename or abs_filename, "calling save on unnamed doc without absolute path")
|
||||
end
|
||||
local fp
|
||||
local output = ""
|
||||
if not self.convert then
|
||||
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
|
||||
else
|
||||
output = table.concat(self.lines);
|
||||
if self.crlf then output = output:gsub("\n", "\r\n") end
|
||||
end
|
||||
local conversion_error = false
|
||||
if self.convert then
|
||||
local errmsg
|
||||
output, errmsg = encoding.convert(self.encoding, "UTF-8", output, {
|
||||
strict = true,
|
||||
handle_to_bom = true
|
||||
})
|
||||
if output then
|
||||
fp = assert( io.open(filename, "wb") )
|
||||
fp:write(encoding.get_charset_bom(self.encoding) .. output)
|
||||
fp:close()
|
||||
else
|
||||
conversion_error = true
|
||||
core.error("%s", errmsg)
|
||||
end
|
||||
else
|
||||
fp:close()
|
||||
end
|
||||
self:set_filename(filename, abs_filename)
|
||||
if not conversion_error then
|
||||
self.new_file = false
|
||||
else
|
||||
self.new_file = true
|
||||
end
|
||||
self:clean()
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Register command to change current document encoding.
|
||||
--------------------------------------------------------------------------------
|
||||
command.add("core.docview", {
|
||||
["doc:change-encoding"] = function(dv)
|
||||
encodings.select_encoding("Select Output Encoding", function(charset)
|
||||
dv.doc.encoding = charset
|
||||
if charset ~= "UTF-8" and charset ~= "ASCII"
|
||||
and charset ~= "US-ASCII" and charset ~= "ISO-8859-1"
|
||||
then
|
||||
dv.doc.convert = true
|
||||
else
|
||||
dv.doc.convert = false
|
||||
end
|
||||
dv.doc:save()
|
||||
end)
|
||||
end,
|
||||
|
||||
["doc:reload-with-encoding"] = function(dv)
|
||||
encodings.select_encoding("Reload With Encoding", function(charset)
|
||||
dv.doc.encoding = charset
|
||||
if charset ~= "UTF-8" and charset ~= "ASCII"
|
||||
and charset ~= "US-ASCII" and charset ~= "ISO-8859-1"
|
||||
then
|
||||
dv.doc.convert = true
|
||||
else
|
||||
dv.doc.convert = false
|
||||
end
|
||||
dv.doc:reload()
|
||||
end)
|
||||
end
|
||||
})
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Register a statusbar item to view change current doc encoding.
|
||||
--------------------------------------------------------------------------------
|
||||
core.status_view:add_item({
|
||||
predicate = function()
|
||||
return core.active_view:is(DocView)
|
||||
and not core.active_view:is(CommandView)
|
||||
end,
|
||||
name = "doc:encoding",
|
||||
alignment = StatusView.Item.RIGHT,
|
||||
get_item = function()
|
||||
local dv = core.active_view
|
||||
return {
|
||||
style.text, dv.doc.encoding or "none"
|
||||
}
|
||||
end,
|
||||
command = function(button)
|
||||
if button == "left" then
|
||||
command.perform "doc:change-encoding"
|
||||
elseif button == "right" then
|
||||
command.perform "doc:reload-with-encoding"
|
||||
end
|
||||
end,
|
||||
tooltip = "encoding"
|
||||
})
|
||||
|
||||
|
||||
return encodings;
|
|
@ -0,0 +1,100 @@
|
|||
-- mod-version:3
|
||||
local config = require "core.config"
|
||||
local common = require "core.common"
|
||||
local DocView = require "core.docview"
|
||||
|
||||
|
||||
config.plugins.colorpreview = common.merge({
|
||||
enabled = true,
|
||||
-- The config specification used by the settings gui
|
||||
config_spec = {
|
||||
name = "Color Preview",
|
||||
{
|
||||
label = "Enable",
|
||||
description = "Enable or disable the color preview feature.",
|
||||
path = "enabled",
|
||||
type = "toggle",
|
||||
default = true
|
||||
}
|
||||
}
|
||||
}, config.plugins.colorpreview)
|
||||
|
||||
local white = { common.color "#ffffff" }
|
||||
local black = { common.color "#000000" }
|
||||
local tmp = {}
|
||||
|
||||
|
||||
-- Workaround for bug in Lite XL 2.1
|
||||
-- Remove this when b029f5993edb7dee5ccd2ba55faac1ec22e24609 is in a release
|
||||
local function get_selection(doc, sort)
|
||||
local line1, col1, line2, col2 = doc:get_selection_idx(doc.last_selection)
|
||||
if line1 then
|
||||
return doc:get_selection_idx(doc.last_selection, sort)
|
||||
else
|
||||
return doc:get_selection_idx(1, sort)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function draw_color_previews(self, line, x, y, ptn, base, nibbles)
|
||||
local text = self.doc.lines[line]
|
||||
local s, e = 0, 0
|
||||
|
||||
while true do
|
||||
s, e = text:find(ptn, e + 1)
|
||||
if not s then break end
|
||||
|
||||
local str = text:sub(s, e)
|
||||
local r, g, b, a = str:match(ptn)
|
||||
r, g, b = tonumber(r, base), tonumber(g, base), tonumber(b, base)
|
||||
a = tonumber(a or "", base)
|
||||
if a ~= nil then
|
||||
if base ~= 16 then
|
||||
a = a * 0xff
|
||||
end
|
||||
else
|
||||
a = 0xff
|
||||
end
|
||||
|
||||
-- #123 becomes #112233
|
||||
if nibbles then
|
||||
r = r * 16
|
||||
g = g * 16
|
||||
b = b * 16
|
||||
end
|
||||
|
||||
local x1 = x + self:get_col_x_offset(line, s)
|
||||
local x2 = x + self:get_col_x_offset(line, e + 1)
|
||||
local oy = self:get_line_text_y_offset()
|
||||
|
||||
local text_color = math.max(r, g, b) < 128 and white or black
|
||||
tmp[1], tmp[2], tmp[3], tmp[4] = r, g, b, a
|
||||
|
||||
local l1, _, l2, _ = get_selection(self.doc, true)
|
||||
|
||||
if not (self.doc:has_selection() and line >= l1 and line <= l2) then
|
||||
renderer.draw_rect(x1, y, x2 - x1, self:get_line_height(), tmp)
|
||||
renderer.draw_text(self:get_font(), str, x1, y + oy, text_color)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local draw_line_text = DocView.draw_line_text
|
||||
|
||||
function DocView:draw_line_text(line, x, y)
|
||||
local lh = draw_line_text(self, line, x, y)
|
||||
if config.plugins.colorpreview.enabled then
|
||||
draw_color_previews(self, line, x, y,
|
||||
"#(%x%x)(%x%x)(%x%x)(%x?%x?)%f[%W]",
|
||||
16
|
||||
)
|
||||
-- support #fff css format
|
||||
draw_color_previews(self, line, x, y, "#(%x)(%x)(%x)%f[%W]", 16, true)
|
||||
draw_color_previews(self, line, x, y,
|
||||
"rgba?%((%d+)%D+(%d+)%D+(%d+)[%s,]-([%.%d]-)%s-%)",
|
||||
nil
|
||||
)
|
||||
end
|
||||
return lh
|
||||
end
|
|
@ -0,0 +1,156 @@
|
|||
-- mod-version:3
|
||||
|
||||
--[[
|
||||
Author: techie-guy
|
||||
|
||||
Plugin to customize the caret in the editor
|
||||
Thanks to @Guldoman for the initial example on Discord
|
||||
|
||||
Features
|
||||
Change the Color and Opacity of the caret
|
||||
Change the Shape of the caret, available shapes are Line, Block, Underline
|
||||
|
||||
Customizing the Caret: (this can be changed from the .config/lite-xl/init.lua
|
||||
file or from the settings menu plugin)
|
||||
config.plugins.custom_caret.shape - Change the shape of the caret [string]
|
||||
style.caret - Change the rgba color of the caret [table]
|
||||
|
||||
Example Config(in the .config/lite-xl/init.lua)
|
||||
style.caret = {0, 255, 255, 150}
|
||||
config.plugins.custom_caret.shape = "block"
|
||||
]]
|
||||
|
||||
local core = require "core"
|
||||
local style = require "core.style"
|
||||
local common = require "core.common"
|
||||
local config = require "core.config"
|
||||
local DocView = require "core.docview"
|
||||
|
||||
config.plugins.custom_caret = common.merge({
|
||||
shape = "line",
|
||||
custom_color = true,
|
||||
color_r = style.caret[1],
|
||||
color_g = style.caret[2],
|
||||
color_b = style.caret[3],
|
||||
opacity = style.caret[4]
|
||||
}, config.plugins.custom_caret)
|
||||
|
||||
-- Reference to plugin config
|
||||
local conf = config.plugins.custom_caret
|
||||
|
||||
-- Get real default caret color after everything is loaded up
|
||||
core.add_thread(function()
|
||||
if
|
||||
conf.color_r == 147 and conf.color_g == 221
|
||||
and
|
||||
conf.color_b == 250 and conf.opacity == 255
|
||||
and
|
||||
(
|
||||
style.caret[1] ~= conf.color_r or style.caret[2] ~= conf.color_g
|
||||
or
|
||||
style.caret[3] ~= conf.color_b or style.caret[4] ~= conf.opacity
|
||||
)
|
||||
then
|
||||
conf.color_r = style.caret[1]
|
||||
conf.color_g = style.caret[2]
|
||||
conf.color_b = style.caret[3]
|
||||
conf.opacity = style.caret[4]
|
||||
end
|
||||
|
||||
local settings_loaded, settings = pcall(require, "plugins.settings")
|
||||
if settings_loaded then
|
||||
conf.config_spec = {
|
||||
name = "Custom Caret",
|
||||
{
|
||||
label = "Shape",
|
||||
description = "The Shape of the cursor.",
|
||||
path = "shape",
|
||||
type = "selection",
|
||||
default = "line",
|
||||
values = {
|
||||
{"Line", "line"},
|
||||
{"Block", "block"},
|
||||
{"Underline", "underline"}
|
||||
}
|
||||
},
|
||||
{
|
||||
label = "Custom Color",
|
||||
description = "Use a custom color for the caret as specified below.",
|
||||
path = "custom_color",
|
||||
type = "toggle",
|
||||
default = true
|
||||
},
|
||||
{
|
||||
label = "Red Component of Color",
|
||||
description = "The color consists of 3 components RGB, "
|
||||
.. "This modifies the 'R' component of the caret's color",
|
||||
path = "color_r",
|
||||
type = "number",
|
||||
min = 0,
|
||||
max = 255,
|
||||
default = style.caret[1],
|
||||
step = 1,
|
||||
},
|
||||
{
|
||||
label = "Green Component of Color",
|
||||
description = "The color consists of 3 components RGB, "
|
||||
.. "This modifies the 'G' component of the caret's color",
|
||||
path = "color_g",
|
||||
type = "number",
|
||||
min = 0,
|
||||
max = 255,
|
||||
default = style.caret[2],
|
||||
step = 1,
|
||||
},
|
||||
{
|
||||
label = "Blue Component of Color",
|
||||
description = "The color consists of 3 components RGB, "
|
||||
.. "This modifies the 'B' component of the caret's color",
|
||||
path = "color_b",
|
||||
type = "number",
|
||||
min = 0,
|
||||
max = 255,
|
||||
default = style.caret[3],
|
||||
step = 1,
|
||||
},
|
||||
{
|
||||
label = "Opacity of the Cursor",
|
||||
description = "The Opacity of the caret",
|
||||
path = "opacity",
|
||||
type = "number",
|
||||
min = 0,
|
||||
max = 255,
|
||||
default = style.caret[4],
|
||||
step = 1,
|
||||
},
|
||||
}
|
||||
|
||||
---@cast settings plugins.settings
|
||||
settings.ui:enable_plugin("custom_caret")
|
||||
end
|
||||
end)
|
||||
|
||||
function DocView:draw_caret(x, y)
|
||||
local caret_width = style.caret_width
|
||||
local caret_height = self:get_line_height()
|
||||
local current_caret_shape = conf.shape
|
||||
local caret_color = conf.custom_color and {
|
||||
conf.color_r,
|
||||
conf.color_g,
|
||||
conf.color_b,
|
||||
conf.opacity
|
||||
} or style.caret
|
||||
|
||||
if (current_caret_shape == "block") then
|
||||
caret_width = math.ceil(self:get_font():get_width("a"))
|
||||
elseif (current_caret_shape == "underline") then
|
||||
caret_width = math.ceil(self:get_font():get_width("a"))
|
||||
caret_height = style.caret_width*2
|
||||
y = y+self:get_line_height()
|
||||
else
|
||||
caret_width = style.caret_width
|
||||
caret_height = self:get_line_height()
|
||||
end
|
||||
|
||||
renderer.draw_rect(x, y, caret_width, caret_height, caret_color)
|
||||
end
|
|
@ -0,0 +1,61 @@
|
|||
# EditorConfig
|
||||
|
||||
This plugin implements the [EditorConfig](https://editorconfig.org/) spec
|
||||
purely on lua by leveraging lua patterns and the regex engine on lite-xl.
|
||||
Installing additional dependencies is not required.
|
||||
|
||||
The EditorConfig spec was implemented as best understood,
|
||||
if you find any bugs please report them on this repository
|
||||
[issue tracker](https://github.com/lite-xl/lite-xl-plugins/issues).
|
||||
|
||||
## Implemented Features
|
||||
|
||||
Global options:
|
||||
|
||||
* root - prevents upward searching of .editorconfig files
|
||||
|
||||
Applied to documents indent info:
|
||||
|
||||
* indent_style
|
||||
* indent_size
|
||||
* tab_width
|
||||
|
||||
Applied on document save:
|
||||
|
||||
* end_of_line - if set to `cr` it is ignored
|
||||
* trim_trailing_whitespace
|
||||
* insert_final_newline boolean
|
||||
|
||||
## Not implemented
|
||||
|
||||
* charset - this feature would need the encoding
|
||||
[PR](https://github.com/lite-xl/lite-xl/pull/1161) or
|
||||
[plugin](https://github.com/jgmdev/lite-xl-encoding)
|
||||
|
||||
## Extras
|
||||
|
||||
* Supports multiple project directories
|
||||
* Implements hot reloading, so modifying an .editorconfig file from within
|
||||
the editor will re-apply all rules to currently opened files.
|
||||
|
||||
## Testing
|
||||
|
||||
This plugin includes a test suite to check how well the .editorconfig parser
|
||||
is working.
|
||||
|
||||
The [editorconfig-core-test](https://github.com/editorconfig/editorconfig-core-test)
|
||||
glob, parser and properties cmake tests where ported and we are getting a 100%
|
||||
pass rate.
|
||||
|
||||
If you are interested in running the test suite, from the terminal execute
|
||||
the following:
|
||||
|
||||
```sh
|
||||
lite-xl test editorconfig
|
||||
```
|
||||
|
||||
To inspect the generated sections and regex rules:
|
||||
|
||||
```sh
|
||||
lite-xl test editorconfig --parsers
|
||||
```
|
|
@ -0,0 +1,441 @@
|
|||
-- mod-version:3
|
||||
--
|
||||
-- EditorConfig plugin for Lite XL
|
||||
-- @copyright Jefferson Gonzalez <jgmdev@gmail.com>
|
||||
-- @license MIT
|
||||
--
|
||||
-- Note: this plugin needs to be loaded after detectindent plugin,
|
||||
-- since the name editorconfig.lua is ordered after detectindent.lua
|
||||
-- there shouldn't be any issues. Just a reminder for the future in
|
||||
-- case of a plugin that could also handle document identation type
|
||||
-- and size, and has a name with more weight than this plugin.
|
||||
--
|
||||
local core = require "core"
|
||||
local common = require "core.common"
|
||||
local config = require "core.config"
|
||||
local trimwhitespace = require "plugins.trimwhitespace"
|
||||
local Doc = require "core.doc"
|
||||
local Parser = require "plugins.editorconfig.parser"
|
||||
|
||||
---@class config.plugins.editorconfig
|
||||
---@field debug boolean
|
||||
config.plugins.editorconfig = common.merge({
|
||||
debug = false,
|
||||
-- The config specification used by the settings gui
|
||||
config_spec = {
|
||||
name = "EditorConfig",
|
||||
{
|
||||
label = "Debug",
|
||||
description = "Display debugging messages on the log.",
|
||||
path = "debug",
|
||||
type = "toggle",
|
||||
default = false
|
||||
}
|
||||
}
|
||||
}, config.plugins.editorconfig)
|
||||
|
||||
---Cache of .editorconfig options to reduce parsing for every opened file.
|
||||
---@type table<string, plugins.editorconfig.parser>
|
||||
local project_configs = {}
|
||||
|
||||
---Keep track of main project directory so when changed we can assign a new
|
||||
---.editorconfig object if neccesary.
|
||||
---@type string
|
||||
local main_project = core.project_dir
|
||||
|
||||
---Functionality that will be exposed by the plugin.
|
||||
---@class plugins.editorconfig
|
||||
local editorconfig = {}
|
||||
|
||||
---Load global .editorconfig options for a project.
|
||||
---@param project_dir string
|
||||
---@return boolean loaded
|
||||
function editorconfig.load(project_dir)
|
||||
local editor_config = project_dir .. "/" .. ".editorconfig"
|
||||
local file = io.open(editor_config)
|
||||
if file then
|
||||
file:close()
|
||||
project_configs[project_dir] = Parser.new(editor_config)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
---Helper to add or substract final new line, it also makes final new line
|
||||
---visble which lite-xl does not.
|
||||
---@param doc core.doc
|
||||
---@param raw? boolean If true does not register change on undo stack
|
||||
---@return boolean handled_new_line
|
||||
local function handle_final_new_line(doc, raw)
|
||||
local handled = false
|
||||
---@diagnostic disable-next-line
|
||||
if doc.insert_final_newline then
|
||||
handled = true
|
||||
if doc.lines[#doc.lines] ~= "\n" then
|
||||
if not raw then
|
||||
doc:insert(#doc.lines, math.huge, "\n")
|
||||
else
|
||||
table.insert(doc.lines, "\n")
|
||||
end
|
||||
end
|
||||
---@diagnostic disable-next-line
|
||||
elseif type(doc.insert_final_newline) == "boolean" then
|
||||
handled = true
|
||||
if trimwhitespace.trim_empty_end_lines then
|
||||
trimwhitespace.trim_empty_end_lines(doc, raw)
|
||||
-- TODO: remove this once 2.1.1 is released
|
||||
else
|
||||
for _=#doc.lines, 1, -1 do
|
||||
local l = #doc.lines
|
||||
if l > 1 and doc.lines[l] == "\n" then
|
||||
local current_line = doc:get_selection()
|
||||
if current_line == l then
|
||||
doc:set_selection(l-1, math.huge, l-1, math.huge)
|
||||
end
|
||||
if not raw then
|
||||
doc:remove(l-1, math.huge, l, math.huge)
|
||||
else
|
||||
table.remove(doc.lines, l)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return handled
|
||||
end
|
||||
|
||||
---Split the given relative path by / or \ separators.
|
||||
---@param path string The path to split
|
||||
---@return table
|
||||
local function split_path(path)
|
||||
local result = {};
|
||||
for match in (path.."/"):gmatch("(.-)".."[:\\/]") do
|
||||
table.insert(result, match);
|
||||
end
|
||||
return result;
|
||||
end
|
||||
|
||||
---Check if the given file path exists.
|
||||
---@param file_path string
|
||||
local function file_exists(file_path)
|
||||
local file = io.open(file_path, "r")
|
||||
if not file then return false end
|
||||
file:close()
|
||||
return true
|
||||
end
|
||||
|
||||
---Merge a config options to target if they don't already exists on target.
|
||||
---@param config_target? plugins.editorconfig.parser.section
|
||||
---@param config_from? plugins.editorconfig.parser.section
|
||||
local function merge_config(config_target, config_from)
|
||||
if config_target and config_from then
|
||||
for name, value in pairs(config_from) do
|
||||
if type(config_target[name]) == "nil" then
|
||||
config_target[name] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---Scan for .editorconfig files from current file path to upper project path
|
||||
---if root attribute is not found first and returns matching config.
|
||||
---@param file_path string
|
||||
---@return plugins.editorconfig.parser.section?
|
||||
local function recursive_get_config(file_path)
|
||||
local project_dir = ""
|
||||
|
||||
local root_config
|
||||
for path, editor_config in pairs(project_configs) do
|
||||
if common.path_belongs_to(file_path, path) then
|
||||
project_dir = path
|
||||
root_config = editor_config:getConfig(
|
||||
common.relative_path(path, file_path)
|
||||
)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if project_dir == "" then
|
||||
for _, project in ipairs(core.project_directories) do
|
||||
if common.path_belongs_to(file_path, project.name) then
|
||||
project_dir = project.name
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local relative_file_path = common.relative_path(project_dir, file_path)
|
||||
local dir = common.dirname(relative_file_path)
|
||||
|
||||
local editor_config = {}
|
||||
local config_found = false
|
||||
if not dir and root_config then
|
||||
editor_config = root_config
|
||||
config_found = true
|
||||
elseif dir then
|
||||
local path_list = split_path(dir)
|
||||
local root_found = false
|
||||
for p=#path_list, 1, -1 do
|
||||
local path = project_dir .. "/" .. table.concat(path_list, "/", 1, p)
|
||||
if file_exists(path .. "/" .. ".editorconfig") then
|
||||
---@type plugins.editorconfig.parser
|
||||
local parser = Parser.new(path .. "/" .. ".editorconfig")
|
||||
local pconfig = parser:getConfig(common.relative_path(path, file_path))
|
||||
if pconfig then
|
||||
merge_config(editor_config, pconfig)
|
||||
config_found = true
|
||||
end
|
||||
if parser.root then
|
||||
root_found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if not root_found and root_config then
|
||||
merge_config(editor_config, root_config)
|
||||
config_found = true
|
||||
end
|
||||
end
|
||||
|
||||
-- clean unset options
|
||||
if config_found then
|
||||
local all_unset = true
|
||||
for name, value in pairs(editor_config) do
|
||||
if value == "unset" then
|
||||
editor_config[name] = nil
|
||||
else
|
||||
all_unset = false
|
||||
end
|
||||
end
|
||||
if all_unset then config_found = false end
|
||||
end
|
||||
|
||||
return config_found and editor_config or nil
|
||||
end
|
||||
|
||||
---Apply editorconfig rules to given doc if possible.
|
||||
---@param doc core.doc
|
||||
function editorconfig.apply(doc)
|
||||
if not doc.abs_filename and not doc.filename then return end
|
||||
local file_path = doc.abs_filename or (main_project .. "/" .. doc.filename)
|
||||
local options = recursive_get_config(file_path)
|
||||
if options then
|
||||
if config.plugins.editorconfig.debug then
|
||||
core.log_quiet(
|
||||
"[EditorConfig]: %s applied %s",
|
||||
file_path, common.serialize(options, {pretty = true})
|
||||
)
|
||||
end
|
||||
local indent_type, indent_size = doc:get_indent_info()
|
||||
if options.indent_style then
|
||||
if options.indent_style == "tab" then
|
||||
indent_type = "hard"
|
||||
else
|
||||
indent_type = "soft"
|
||||
end
|
||||
end
|
||||
|
||||
if options.indent_size and options.indent_size == "tab" then
|
||||
if options.tab_width then
|
||||
options.indent_size = options.tab_width
|
||||
else
|
||||
options.indent_size = config.indent_size or 2
|
||||
end
|
||||
end
|
||||
|
||||
if options.indent_size then
|
||||
indent_size = options.indent_size
|
||||
end
|
||||
|
||||
if doc.indent_info then
|
||||
doc.indent_info.type = indent_type
|
||||
doc.indent_info.size = indent_size
|
||||
doc.indent_info.confirmed = true
|
||||
else
|
||||
doc.indent_info = {
|
||||
type = indent_type,
|
||||
size = indent_size,
|
||||
confirmed = true
|
||||
}
|
||||
end
|
||||
|
||||
if options.end_of_line then
|
||||
if options.end_of_line == "crlf" then
|
||||
doc.crlf = true
|
||||
elseif options.end_of_line == "lf" then
|
||||
doc.crlf = false
|
||||
end
|
||||
end
|
||||
|
||||
if options.trim_trailing_whitespace then
|
||||
doc.trim_trailing_whitespace = true
|
||||
elseif options.trim_trailing_whitespace == false then
|
||||
doc.trim_trailing_whitespace = false
|
||||
else
|
||||
doc.trim_trailing_whitespace = nil
|
||||
end
|
||||
|
||||
if options.insert_final_newline then
|
||||
doc.insert_final_newline = true
|
||||
elseif options.insert_final_newline == false then
|
||||
doc.insert_final_newline = false
|
||||
else
|
||||
doc.insert_final_newline = nil
|
||||
end
|
||||
|
||||
if
|
||||
(
|
||||
type(doc.trim_trailing_whitespace) == "boolean"
|
||||
or
|
||||
type(doc.insert_final_newline) == "boolean"
|
||||
)
|
||||
-- TODO: remove this once 2.1.1 is released
|
||||
and
|
||||
trimwhitespace.disable
|
||||
then
|
||||
trimwhitespace.disable(doc)
|
||||
end
|
||||
|
||||
handle_final_new_line(doc, true)
|
||||
end
|
||||
end
|
||||
|
||||
---Applies .editorconfig options to all open documents if possible.
|
||||
function editorconfig.apply_all()
|
||||
for _, doc in ipairs(core.docs) do
|
||||
editorconfig.apply(doc)
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Load .editorconfig on all projects loaded at startup and apply it
|
||||
--------------------------------------------------------------------------------
|
||||
core.add_thread(function()
|
||||
local loaded = false
|
||||
|
||||
-- scan all opened project directories
|
||||
if core.project_directories then
|
||||
for i=1, #core.project_directories do
|
||||
local found = editorconfig.load(core.project_directories[i].name)
|
||||
if found then loaded = true end
|
||||
end
|
||||
end
|
||||
|
||||
-- if an editorconfig was found then try to apply it to opened docs
|
||||
if loaded then
|
||||
editorconfig.apply_all()
|
||||
end
|
||||
end)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Override various core project loading functions for .editorconfig scanning
|
||||
--------------------------------------------------------------------------------
|
||||
local core_open_folder_project = core.open_folder_project
|
||||
function core.open_folder_project(directory)
|
||||
core_open_folder_project(directory)
|
||||
if project_configs[main_project] then project_configs[main_project] = nil end
|
||||
main_project = core.project_dir
|
||||
editorconfig.load(main_project)
|
||||
end
|
||||
|
||||
local core_remove_project_directory = core.remove_project_directory
|
||||
function core.remove_project_directory(path)
|
||||
local out = core_remove_project_directory(path)
|
||||
if project_configs[path] then project_configs[path] = nil end
|
||||
return out
|
||||
end
|
||||
|
||||
local core_add_project_directory = core.add_project_directory
|
||||
function core.add_project_directory(directory)
|
||||
local out = core_add_project_directory(directory)
|
||||
editorconfig.load(directory)
|
||||
return out
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Hook into the core.doc to apply editor config options
|
||||
--------------------------------------------------------------------------------
|
||||
local doc_new = Doc.new
|
||||
function Doc:new(...)
|
||||
doc_new(self, ...)
|
||||
editorconfig.apply(self)
|
||||
end
|
||||
|
||||
---Cloned trimwitespace plugin until it is exposed for other plugins.
|
||||
---@param doc core.doc
|
||||
local function trim_trailing_whitespace(doc)
|
||||
if trimwhitespace.trim then
|
||||
trimwhitespace.trim(doc)
|
||||
return
|
||||
end
|
||||
|
||||
-- TODO: remove this once 2.1.1 is released
|
||||
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
|
||||
|
||||
local doc_save = Doc.save
|
||||
function Doc:save(...)
|
||||
local new_file = self.new_file
|
||||
|
||||
---@diagnostic disable-next-line
|
||||
if self.trim_trailing_whitespace then
|
||||
trim_trailing_whitespace(self)
|
||||
end
|
||||
|
||||
local lc = #self.lines
|
||||
local handle_new_line = handle_final_new_line(self)
|
||||
|
||||
-- remove the unnecesary visible \n\n or the disabled \n
|
||||
if handle_new_line then
|
||||
self.lines[lc] = self.lines[lc]:gsub("\n$", "")
|
||||
end
|
||||
|
||||
doc_save(self, ...)
|
||||
|
||||
-- restore the visible \n\n or disabled \n
|
||||
if handle_new_line then
|
||||
self.lines[lc] = self.lines[lc] .. "\n"
|
||||
end
|
||||
|
||||
if common.basename(self.abs_filename) == ".editorconfig" then
|
||||
-- blindlessly reload related project .editorconfig options
|
||||
for _, project in ipairs(core.project_directories) do
|
||||
if common.path_belongs_to(self.abs_filename, project.name) then
|
||||
editorconfig.load(project.name)
|
||||
break
|
||||
end
|
||||
end
|
||||
-- re-apply editorconfig options to all open files
|
||||
editorconfig.apply_all()
|
||||
elseif new_file then
|
||||
-- apply editorconfig options for file that was previously unsaved
|
||||
editorconfig.apply(self)
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Run the test suite if requested on CLI with: lite-xl test editorconfig
|
||||
--------------------------------------------------------------------------------
|
||||
for i, argument in ipairs(ARGS) do
|
||||
if argument == "test" and ARGS[i+1] == "editorconfig" then
|
||||
require "plugins.editorconfig.runtest"
|
||||
os.exit()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return editorconfig
|
|
@ -0,0 +1,553 @@
|
|||
-- Lua parser implementation of the .editorconfig spec as best understood.
|
||||
-- @copyright Jefferson Gonzalez <jgmdev@gmail.com>
|
||||
-- @license MIT
|
||||
|
||||
local core = require "core"
|
||||
local config = require "core.config"
|
||||
|
||||
local STANDALONE = false
|
||||
for i, argument in ipairs(ARGS) do
|
||||
if argument == "test" and ARGS[i+1] == "editorconfig" then
|
||||
STANDALONE = true
|
||||
end
|
||||
end
|
||||
|
||||
---Logger that will output using lite-xl logging functions or print to
|
||||
---terminal if the parser is running in standalone mode.
|
||||
---@param type "log" | "error"
|
||||
---@param format string
|
||||
---@param ... any
|
||||
local function log(type, format, ...)
|
||||
if not STANDALONE then
|
||||
core[type]("[EditorConfig]: " .. format, ...)
|
||||
else
|
||||
print("[" .. type:upper() .. "]: " .. string.format(format, ...))
|
||||
end
|
||||
end
|
||||
|
||||
---Represents an .editorconfig path rule/expression.
|
||||
---@class plugins.editorconfig.parser.rule
|
||||
---Path expression as found between square brackets.
|
||||
---@field expression string | table<integer,string>
|
||||
---The expression converted to a regex.
|
||||
---@field regex string | table<integer,string>
|
||||
---@field regex_compiled any? | table<integer,string>
|
||||
---@field negation boolean Indicates that the expression is a negation.
|
||||
---@field ranges table<integer,number> List of ranges found on the expression.
|
||||
|
||||
---Represents a section of the .editorconfig with all its config options.
|
||||
---@class plugins.editorconfig.parser.section
|
||||
---@field rule plugins.editorconfig.parser.rule
|
||||
---@field equivalent_rules plugins.editorconfig.parser.rule[]
|
||||
---@field indent_style "tab" | "space"
|
||||
---@field indent_size integer
|
||||
---@field tab_width integer
|
||||
---@field end_of_line "lf" | "cr" | "crlf"
|
||||
---@field charset "latin1" | "utf-8" | "utf-8-bom" | "utf-16be" | "utf-16le"
|
||||
---@field trim_trailing_whitespace boolean
|
||||
---@field insert_final_newline boolean
|
||||
|
||||
---EditorConfig parser class and filename config matching.
|
||||
---@class plugins.editorconfig.parser
|
||||
---@field config_path string
|
||||
---@field sections plugins.editorconfig.parser.section[]
|
||||
---@field root boolean
|
||||
local Parser = {}
|
||||
Parser.__index = Parser
|
||||
|
||||
---Constructor
|
||||
---@param config_path string
|
||||
---@return plugins.editorconfig.parser
|
||||
function Parser.new(config_path)
|
||||
local self = {}
|
||||
setmetatable(self, Parser)
|
||||
self.config_path = config_path
|
||||
self.sections = {}
|
||||
self.root = false
|
||||
self:read()
|
||||
return self
|
||||
end
|
||||
|
||||
--- char to hex cache and automatic converter
|
||||
---@type table<string,string>
|
||||
local hex_value = {}
|
||||
setmetatable(hex_value, {
|
||||
__index = function(t, k)
|
||||
local v = rawget(t, k)
|
||||
if v == nil then
|
||||
v = string.format("%x", string.byte(k))
|
||||
rawset(t, k, v)
|
||||
end
|
||||
return v
|
||||
end
|
||||
})
|
||||
|
||||
---Simplifies managing rules with other inner rules like {...} which can
|
||||
---contain escaped \\{ \\} and expressions that are easier handled after
|
||||
---converting the escaped special characters to \xXX counterparts.
|
||||
---@param value string
|
||||
---@return string escaped_values
|
||||
local function escapes_to_regex_hex(value)
|
||||
local escaped_chars = {}
|
||||
for char in value:ugmatch("\\(.)") do
|
||||
table.insert(escaped_chars, char)
|
||||
end
|
||||
for _, char in ipairs(escaped_chars) do
|
||||
value = value:ugsub("\\" .. char, "\\x" .. hex_value[char])
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
---An .editorconfig path expression to regex conversion rule.
|
||||
---@class rule
|
||||
---@field rule string Lua pattern.
|
||||
---Callback conversion function.
|
||||
---@field conversion fun(match:string, section:plugins.editorconfig.parser.section):string
|
||||
|
||||
---List of conversion rules applied to brace expressions.
|
||||
---@type rule[]
|
||||
local RULES_BRACES = {
|
||||
{ rule = "^%(", conversion = function() return "\\(" end },
|
||||
{ rule = "^%)", conversion = function() return "\\)" end },
|
||||
{ rule = "^%.", conversion = function() return "\\." end },
|
||||
{ rule = "^\\%[", conversion = function() return "\\[" end },
|
||||
{ rule = "^\\%]", conversion = function() return "\\]" end },
|
||||
{ rule = "^\\!", conversion = function() return "!" end },
|
||||
{ rule = "^\\;", conversion = function() return ";" end },
|
||||
{ rule = "^\\#", conversion = function() return "#" end },
|
||||
{ rule = "^\\,", conversion = function() return "," end },
|
||||
{ rule = "^\\{", conversion = function() return "{" end },
|
||||
{ rule = "^\\}", conversion = function() return "}" end },
|
||||
{ rule = "^,", conversion = function() return "|" end },
|
||||
{ rule = "^\\%*", conversion = function() return "\\*" end },
|
||||
{ rule = "^%*", conversion = function() return "[^\\/]*" end },
|
||||
{ rule = "^%*%*", conversion = function() return ".*" end },
|
||||
{ rule = "^%?", conversion = function() return "." end },
|
||||
{ rule = "^{}", conversion = function() return "{}" end },
|
||||
{ rule = "^{[^,]+}", conversion = function(match) return match end },
|
||||
{ rule = "^%b{}",
|
||||
conversion = function(match)
|
||||
local out = match:ugsub("%(", "\\(")
|
||||
:ugsub("%)", "\\)")
|
||||
:ugsub("%.", "\\.")
|
||||
:ugsub("\\%[", "[\\[]")
|
||||
:ugsub("\\%]", "[\\]]")
|
||||
:ugsub("^\\!", "!")
|
||||
:ugsub("^\\;", ";")
|
||||
:ugsub("^\\#", "#")
|
||||
-- negation chars list
|
||||
:ugsub("%[!(%a+)%]", "[^%1]")
|
||||
:ugsub("\\\\", "[\\]")
|
||||
-- escaped braces
|
||||
:ugsub("\\{", "[{]")
|
||||
:ugsub("\\}", "[}]")
|
||||
-- non escaped braces
|
||||
:ugsub("{([^%]])", "(%1")
|
||||
:ugsub("}([^%]])", ")%1")
|
||||
:ugsub("^{", "(")
|
||||
:ugsub("}$", ")")
|
||||
-- escaped globs
|
||||
:ugsub("\\%*", "[\\*]")
|
||||
:ugsub("\\%?", "[\\?]")
|
||||
-- non escaped globs
|
||||
:ugsub("%*%*", "[*][*]") -- prevent this glob from expanding to next sub
|
||||
:ugsub("%*([^%]])", "[^\\/]*%1")
|
||||
:ugsub("%[%*%]%[%*%]", ".*")
|
||||
:ugsub("%?([^%]])", ".%1")
|
||||
-- escaped comma
|
||||
:ugsub("\\,", "[,]")
|
||||
-- non escaped comma
|
||||
:ugsub(",([^%]])", "|%1")
|
||||
return out
|
||||
end
|
||||
},
|
||||
{ rule = "^%[[^/%]]*%]",
|
||||
conversion = function(match)
|
||||
local negation = match:umatch("^%[!")
|
||||
local chars = match:umatch("^%[!?(.-)%]")
|
||||
chars = chars:ugsub("^%-", "\\-"):ugsub("%-$", "\\-")
|
||||
local out = ""
|
||||
if negation then
|
||||
out = "[^"..chars.."]"
|
||||
else
|
||||
out = "["..chars.."]"
|
||||
end
|
||||
return out
|
||||
end
|
||||
},
|
||||
}
|
||||
|
||||
---List of conversion rules applied to .editorconfig path expressions.
|
||||
---@type rule[]
|
||||
local RULES = {
|
||||
-- normalize escaped .editorconfig special chars or keep them escaped
|
||||
{ rule = "^\\x[a-fA-F][a-fA-F]", conversion = function(match) return match end },
|
||||
{ rule = "^\\%*", conversion = function() return "\\*" end },
|
||||
{ rule = "^\\%?", conversion = function() return "\\?" end },
|
||||
{ rule = "^\\{", conversion = function() return "{" end },
|
||||
{ rule = "^\\}", conversion = function() return "}" end },
|
||||
{ rule = "^\\%[", conversion = function() return "\\[" end },
|
||||
{ rule = "^\\%]", conversion = function() return "\\]" end },
|
||||
{ rule = "^\\!", conversion = function() return "!" end },
|
||||
{ rule = "^\\;", conversion = function() return ";" end },
|
||||
{ rule = "^\\#", conversion = function() return "#" end },
|
||||
-- escape special chars
|
||||
{ rule = "^%.", conversion = function() return "\\." end },
|
||||
{ rule = "^%(", conversion = function() return "\\(" end },
|
||||
{ rule = "^%)", conversion = function() return "\\)" end },
|
||||
{ rule = "^%[[^/%]]*%]",
|
||||
conversion = function(match)
|
||||
local negation = match:umatch("^%[!")
|
||||
local chars = match:umatch("^%[!?(.-)%]")
|
||||
chars = chars:ugsub("^%-", "\\-"):ugsub("%-$", "\\-")
|
||||
local out = ""
|
||||
if negation then
|
||||
out = "[^"..chars.."]"
|
||||
else
|
||||
out = "["..chars.."]"
|
||||
end
|
||||
return out
|
||||
end
|
||||
},
|
||||
-- Is this negation rule valid?
|
||||
{ rule = "^!%w+",
|
||||
conversion = function(match)
|
||||
local chars = match:umatch("%w+")
|
||||
return "[^"..chars.."]"
|
||||
end
|
||||
},
|
||||
-- escape square brackets
|
||||
{ rule = "^%[", conversion = function() return "\\[" end },
|
||||
{ rule = "^%]", conversion = function() return "\\]" end },
|
||||
-- match any characters
|
||||
{ rule = "^%*%*", conversion = function() return ".*" end },
|
||||
-- match any characters excluding path separators, \ not needed but just in case
|
||||
{ rule = "^%*", conversion = function() return "[^\\/]*" end },
|
||||
-- match optional character, doesn't matters what or should only be a \w?
|
||||
{ rule = "^%?", conversion = function() return "[^/]" end },
|
||||
-- threat empty braces literally
|
||||
{ rule = "^{}", conversion = function() return "{}" end },
|
||||
-- match a number range
|
||||
{ rule = "^{%-?%d+%.%.%-?%d+}",
|
||||
conversion = function(match, section)
|
||||
local min, max = match:umatch("(-?%d+)%.%.(-?%d+)")
|
||||
min = tonumber(min)
|
||||
max = tonumber(max)
|
||||
if min and max then
|
||||
if not section.rule.ranges then section.rule.ranges = {} end
|
||||
table.insert(section.rule.ranges, {
|
||||
math.min(min, max),
|
||||
math.max(min, max)
|
||||
})
|
||||
end
|
||||
local minus = ""
|
||||
if min < 0 or max < 0 then minus = "\\-?" end
|
||||
return "(?<!0)("..minus.."[1-9]\\d*)"
|
||||
end
|
||||
},
|
||||
-- threat single option braces literally
|
||||
{ rule = "^{[^,]+}", conversion = function(match) return match end },
|
||||
-- match invalid range
|
||||
{ rule = "^{[^%.]+%.%.[^%.]+}", conversion = function(match) return match end },
|
||||
-- match any of the strings separated by commas inside the curly braces
|
||||
{ rule = "^%b{}",
|
||||
conversion = function(rule, section)
|
||||
rule = rule:gsub("^{", ""):gsub("}$", "")
|
||||
local pos, len, exp = 1, rule:ulen(), ""
|
||||
|
||||
while pos <= len do
|
||||
local found = false
|
||||
for _, r in ipairs(RULES_BRACES) do
|
||||
local match = rule:umatch(r.rule, pos)
|
||||
if match then
|
||||
exp = exp .. r.conversion(match, section)
|
||||
pos = pos + match:ulen()
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not found then
|
||||
exp = exp .. rule:usub(pos, pos)
|
||||
pos = pos + 1
|
||||
end
|
||||
end
|
||||
|
||||
return "(" .. exp .. ")"
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
---Adds the regex equivalent of a section path expression.
|
||||
---@param section plugins.editorconfig.parser.section | string
|
||||
---@return plugins.editorconfig.parser.section
|
||||
function Parser:rule_to_regex(section)
|
||||
if type(section) == "string" then
|
||||
section = {rule = {expression = section}}
|
||||
end
|
||||
|
||||
local rule = section.rule.expression
|
||||
|
||||
-- match everything rule which is different from regular *
|
||||
-- that doesn't matches path separators
|
||||
if rule == "*" then
|
||||
section.rule.regex = ".+"
|
||||
section.rule.regex_compiled = regex.compile(".+")
|
||||
return section
|
||||
end
|
||||
|
||||
rule = escapes_to_regex_hex(section.rule.expression)
|
||||
|
||||
local pos, len, exp = 1, rule:ulen(), ""
|
||||
|
||||
-- if expression starts with ! it is treated entirely as a negation
|
||||
local negation = rule:umatch("^%s*!")
|
||||
if negation then
|
||||
pos = pos + negation:ulen() + 1
|
||||
end
|
||||
|
||||
-- apply all conversion rules by looping the path expression/rule
|
||||
while pos <= len do
|
||||
local found = false
|
||||
for _, r in ipairs(RULES) do
|
||||
local match = rule:umatch(r.rule, pos)
|
||||
if match then
|
||||
exp = exp .. r.conversion(match, section)
|
||||
pos = pos + match:ulen()
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not found then
|
||||
exp = exp .. rule:usub(pos, pos)
|
||||
pos = pos + 1
|
||||
end
|
||||
end
|
||||
|
||||
-- force match up to the end
|
||||
exp = exp .. "$"
|
||||
|
||||
-- allow expressions that start with * to match anything on start
|
||||
if exp:match("^%[^\\/%]%*") then
|
||||
exp = exp:gsub("^%[^\\/%]%*", ".*")
|
||||
-- fixes two failing tests
|
||||
elseif exp:match("^%[") then
|
||||
exp = "^" .. exp
|
||||
-- match only on root dir
|
||||
elseif exp:match("^/") then
|
||||
exp = exp:gsub("^/", "^")
|
||||
end
|
||||
|
||||
-- store changes to the section rule
|
||||
section.rule.regex, section.rule.negation = exp, negation
|
||||
section.rule.regex_compiled = regex.compile(section.rule.regex)
|
||||
if not section.rule.regex_compiled then
|
||||
log(
|
||||
"error",
|
||||
"could not compile '[%s]' to regex '%s'",
|
||||
rule, section.rule.regex
|
||||
)
|
||||
end
|
||||
|
||||
return section
|
||||
end
|
||||
|
||||
---Parses the associated .editorconfig file and stores each section.
|
||||
function Parser:read()
|
||||
local file = io.open(self.config_path, "r")
|
||||
|
||||
self.sections = {}
|
||||
|
||||
if not file then
|
||||
log("log", "could not read %s", self.config_path)
|
||||
return
|
||||
end
|
||||
|
||||
---@type plugins.editorconfig.parser.section
|
||||
local section = {}
|
||||
|
||||
for line in file:lines() do
|
||||
---@cast line string
|
||||
|
||||
-- first we try to see if the line is a rule section
|
||||
local rule = ""
|
||||
rule = line:umatch("^%s*%[(.+)%]%s*$")
|
||||
if rule then
|
||||
if section.rule then
|
||||
-- save previous section and crerate new one
|
||||
table.insert(self.sections, section)
|
||||
section = {}
|
||||
end
|
||||
section.rule = {
|
||||
expression = rule
|
||||
}
|
||||
-- convert the expression to a regex directly on the section table
|
||||
self:rule_to_regex(section)
|
||||
|
||||
local clone = rule
|
||||
if clone:match("//+") or clone:match("/%*%*/") then
|
||||
section.equivalent_rules = {}
|
||||
end
|
||||
while clone:match("//+") or clone:match("/%*%*/") do
|
||||
---@type plugins.editorconfig.parser.section[]
|
||||
if clone:match("//+") then
|
||||
clone = clone:ugsub("//+", "/", 1)
|
||||
table.insert(section.equivalent_rules, self:rule_to_regex(clone).rule)
|
||||
end
|
||||
if clone:match("/%*%*/") then
|
||||
clone = clone:ugsub("/%*%*/", "/", 1)
|
||||
table.insert(section.equivalent_rules, self:rule_to_regex(clone).rule)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not rule then
|
||||
local name, value = line:umatch("^%s*(%w%S+)%s*=%s*([^\n\r]+)")
|
||||
if name and value then
|
||||
name = name:ulower()
|
||||
-- do not lowercase property values that start with test_
|
||||
if not name:match("^test_") then
|
||||
value = value:ulower()
|
||||
end
|
||||
if value == "true" then
|
||||
value = true
|
||||
elseif value == "false" then
|
||||
value = false
|
||||
elseif math.tointeger and math.tointeger(value) then
|
||||
value = math.tointeger(value)
|
||||
elseif tonumber(value) then
|
||||
value = tonumber(value)
|
||||
end
|
||||
|
||||
if section.rule then
|
||||
section[name] = value
|
||||
elseif name == "root" and type(value) == "boolean" then
|
||||
self.root = value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if section.rule then
|
||||
table.insert(self.sections, section)
|
||||
end
|
||||
end
|
||||
|
||||
---Helper function that converts a regex offset results into a list
|
||||
---of strings, omitting the first result which is the complete match.
|
||||
---@param offsets table<integer,integer>
|
||||
---@param value string
|
||||
---@return table<integer, string>
|
||||
local function regex_result_to_table(offsets, value)
|
||||
local result = {}
|
||||
local offset_fix = 0
|
||||
if not regex.find_offsets then
|
||||
offset_fix = 1
|
||||
end
|
||||
for i=3, #offsets, 2 do
|
||||
table.insert(result, value:sub(offsets[i], offsets[i+1]-offset_fix))
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
---Get a matching config for the given filename or nil if nothing found.
|
||||
---@param file_name string
|
||||
---@param defaults? boolean Set indent size to defaults when needed,
|
||||
---@return plugins.editorconfig.parser.section?
|
||||
function Parser:getConfig(file_name, defaults)
|
||||
if PLATFORM == "Windows" then
|
||||
file_name = file_name:gsub("\\", "/")
|
||||
end
|
||||
|
||||
local regex_match = regex.match
|
||||
if regex.find_offsets then
|
||||
regex_match = regex.find_offsets
|
||||
end
|
||||
|
||||
local properties = {}
|
||||
|
||||
local found = false
|
||||
for _, section in ipairs(self.sections) do
|
||||
if section.rule.regex_compiled then
|
||||
local negation = section.rule.negation
|
||||
-- default rule
|
||||
local matched = {regex_match(section.rule.regex_compiled, file_name)}
|
||||
-- try equivalent rules if available
|
||||
if not matched[1] and section.equivalent_rules then
|
||||
for _, esection in ipairs(section.equivalent_rules) do
|
||||
matched = {regex_match(esection.regex_compiled, file_name)}
|
||||
if matched[1] then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if (matched[1] and not negation) or (not matched[1] and negation) then
|
||||
local ranges_match = true
|
||||
if section.rule.ranges then
|
||||
local results = regex_result_to_table(matched, file_name)
|
||||
if #results < #section.rule.ranges then
|
||||
ranges_match = false
|
||||
else
|
||||
for i, range in ipairs(section.rule.ranges) do
|
||||
local number = tonumber(results[i])
|
||||
if not number then
|
||||
ranges_match = false
|
||||
break
|
||||
end
|
||||
if number < range[1] or number > range[2] then
|
||||
ranges_match = false
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if ranges_match then
|
||||
found = true
|
||||
for name, value in pairs(section) do
|
||||
if name ~= "rule" and name ~= "equivalent_rules" then
|
||||
properties[name] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if found and defaults then
|
||||
if properties.indent_style and properties.indent_style == "space" then
|
||||
if properties.indent_size and not properties.tab_width then
|
||||
properties.tab_width = 4
|
||||
end
|
||||
elseif properties.indent_style and properties.indent_style == "tab" then
|
||||
if not properties.tab_width and not properties.indent_size then
|
||||
properties.indent_size = "tab"
|
||||
elseif properties.tab_width then
|
||||
properties.indent_size = properties.tab_width
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return found and properties or nil
|
||||
end
|
||||
|
||||
---Get a matching config for the given filename or nil if nothing found.
|
||||
---@param file_name string
|
||||
---@return string
|
||||
function Parser:getConfigString(file_name)
|
||||
local out = ""
|
||||
local properties = self:getConfig(file_name, true)
|
||||
if properties then
|
||||
local config_sorted = {}
|
||||
for name, value in pairs(properties) do
|
||||
table.insert(config_sorted, {name = name, value = value})
|
||||
end
|
||||
table.sort(config_sorted, function(a, b)
|
||||
return a.name < b.name
|
||||
end)
|
||||
for _, value in ipairs(config_sorted) do
|
||||
out = out .. value.name .. "=" .. tostring(value.value) .. "\n"
|
||||
end
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
return Parser
|
|
@ -0,0 +1,63 @@
|
|||
local core = require "core"
|
||||
local tests = require "plugins.editorconfig.tests"
|
||||
|
||||
-- disable print buffer for immediate output
|
||||
io.stdout:setvbuf "no"
|
||||
|
||||
-- overwrite to print into stdout
|
||||
function core.error(format, ...)
|
||||
print(string.format(format, ...))
|
||||
end
|
||||
|
||||
function core.log(format, ...)
|
||||
print(string.format(format, ...))
|
||||
end
|
||||
|
||||
function core.log_quiet(format, ...)
|
||||
print(string.format(format, ...))
|
||||
end
|
||||
|
||||
-- check if --parsers flag was given to only output the path expressions and
|
||||
-- their conversion into regular expressions.
|
||||
local PARSERS = false
|
||||
for _, argument in ipairs(ARGS) do
|
||||
if argument == "--parsers" then
|
||||
PARSERS = true
|
||||
end
|
||||
end
|
||||
|
||||
if not PARSERS then
|
||||
require "plugins.editorconfig.tests.glob"
|
||||
require "plugins.editorconfig.tests.parser"
|
||||
require "plugins.editorconfig.tests.properties"
|
||||
|
||||
tests.run()
|
||||
else
|
||||
-- Globs
|
||||
tests.add_parser(USERDIR .. "/plugins/editorconfig/tests/glob/braces.in")
|
||||
tests.add_parser(USERDIR .. "/plugins/editorconfig/tests/glob/brackets.in")
|
||||
tests.add_parser(USERDIR .. "/plugins/editorconfig/tests/glob/question.in")
|
||||
tests.add_parser(USERDIR .. "/plugins/editorconfig/tests/glob/star.in")
|
||||
tests.add_parser(USERDIR .. "/plugins/editorconfig/tests/glob/star_star.in")
|
||||
tests.add_parser(USERDIR .. "/plugins/editorconfig/tests/glob/utf8char.in")
|
||||
|
||||
-- Parser
|
||||
tests.add_parser(USERDIR .. "/plugins/editorconfig/tests/parser/basic.in")
|
||||
tests.add_parser(USERDIR .. "/plugins/editorconfig/tests/parser/bom.in")
|
||||
tests.add_parser(USERDIR .. "/plugins/editorconfig/tests/parser/comments.in")
|
||||
tests.add_parser(USERDIR .. "/plugins/editorconfig/tests/parser/comments_and_newlines.in")
|
||||
tests.add_parser(USERDIR .. "/plugins/editorconfig/tests/parser/comments_only.in")
|
||||
tests.add_parser(USERDIR .. "/plugins/editorconfig/tests/parser/crlf.in")
|
||||
tests.add_parser(USERDIR .. "/plugins/editorconfig/tests/parser/empty.in")
|
||||
tests.add_parser(USERDIR .. "/plugins/editorconfig/tests/parser/limits.in")
|
||||
tests.add_parser(USERDIR .. "/plugins/editorconfig/tests/parser/newlines_only.in")
|
||||
tests.add_parser(USERDIR .. "/plugins/editorconfig/tests/parser/whitespace.in")
|
||||
|
||||
-- Properties
|
||||
tests.add_parser(USERDIR .. "/plugins/editorconfig/tests/properties/indent_size_default.in")
|
||||
tests.add_parser(USERDIR .. "/plugins/editorconfig/tests/properties/lowercase_names.in")
|
||||
tests.add_parser(USERDIR .. "/plugins/editorconfig/tests/properties/lowercase_values.in")
|
||||
tests.add_parser(USERDIR .. "/plugins/editorconfig/tests/properties/tab_width_default.in")
|
||||
|
||||
tests.run_parsers()
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue