Compare commits
463 Commits
Author | SHA1 | Date |
---|---|---|
George Sokianos | d74688028c | |
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 | |
Jan | 7b67a5d81b | |
Adam Harrison | cca61ab8ec | |
ThaCuber | c45463459c | |
Guldoman | 39993a6d93 | |
Guldoman | a29327e375 | |
Takase | 7111b8a6c9 | |
takase1121 | a9ac33429e | |
takase1121 | ad1fad2632 | |
takase1121 | 79bae532b9 | |
takase1121 | 41813604e1 | |
takase1121 | 7b064bae6b | |
Takase | 2d36359e6e | |
Guldoman | dac8d1ac8e | |
Guldoman | 5719f4de6f | |
Adam | e14af4604a | |
ThaCuber | f43cfc4a94 | |
Guldoman | 234dd40e49 | |
Guldoman | ee02d0e0b6 | |
Guldoman | de043f2e13 | |
Guldoman | 9301220d26 | |
Guldoman | 2571e17d1b | |
Guldoman | 4e2f70e5ee | |
Takase | 52d224ac6b | |
Guldoman | 3ee903b16c | |
Guldoman | 1dceaf65f5 | |
Guldoman | c4f9542509 | |
Daniel Margarido | 86b89c402d | |
Guldoman | 3972f10059 | |
Guldoman | da64a99f18 | |
Takase | dc62c59705 | |
Takase | de05ec374e | |
ThaCuber | df7cf7e270 | |
Guldoman | dc3716f177 | |
Guldoman | 05fbc48e03 | |
Takase | 6370968494 | |
Guldoman | 05e7fc4e43 | |
Takase | e520227d35 | |
Guldoman | 9be4583f63 | |
Guldoman | 7e20424b29 | |
Guldoman | 9612f20685 | |
Guldoman | 1669409610 | |
Takase | 1196bf355c | |
Takase | 9017fadba6 | |
Guldoman | 17cb2e86ed | |
Takase | 4f28f718a9 | |
Guldoman | febfcb5757 | |
Guldoman | e5c17ed3ec | |
Robert Hildebrandt | 351ef1ecea | |
Takase | 15e05aaf03 | |
sammyette | 1d5f7ae9b0 | |
Jefferson González | 27f24701c4 | |
Guldoman | 25a0943087 | |
Adam | b0e1469a87 | |
Guldoman | 2ed17dd03f | |
Jan | 3993d689fb | |
Takase | 3f3b4d52b4 | |
Guldoman | 9bc44e2b45 | |
Guldoman | 50102fdc3a | |
Takase | dc14860166 | |
Adam | eb306a2ff0 | |
Velosofy | f820b9301f | |
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 | |
Takase | 8c8635146e | |
Guldoman | 6d5c6051cd | |
Adam Harrison | 6bb9a89a8b | |
Shreyas A S | 02e421149b | |
Guldoman | 16bfa6d958 | |
Delta-official | 9c9f2dace0 | |
Takase | 8daf7dc926 | |
Adam | 5145194f1f | |
Takase | 6ad67c18f0 | |
Takase | 7ba1d1ba8e | |
Takase | ac3630c2ea | |
Adam | c470683005 | |
Takase | 8c9620aaed | |
Guldoman | 0ebf3c0393 | |
Takase | 74d9c15736 | |
Guldoman | 3775032c78 | |
Guldoman | ca3acd4ee9 | |
Luke aka SwissalpS | 0e5f35ff9f | |
Luke aka SwissalpS | 39319e2ce9 | |
Jan | 6e113cb15e | |
Guldoman | 9bb6589790 | |
Jan | e6c7001b5a | |
Guldoman | 94b4825754 | |
Guldoman | 12a552931e | |
Guldoman | ff38e449d1 | |
Guldoman | 122b72ed90 | |
Guldoman | f80a4563be | |
Guldoman | 862aba0f91 | |
Guldoman | 528e5641fb | |
Jefferson González | 35647067d8 | |
Jefferson González | ba753593f3 | |
takase1121 | 363b102abc | |
takase1121 | 252bf87ead | |
Jefferson González | 431c8f4a36 | |
Adam | 21db8313c1 | |
Guldoman | e7168a1e00 | |
takase1121 | c255e53d37 | |
takase1121 | a007a190ef | |
Adam Harrison | 6714732222 | |
Adam | aa2ac0a4ce | |
takase1121 | 2090afccca | |
Takase | 46260b8073 | |
Jan | 0fae012c68 | |
jgmdev | ff4364b0ff | |
Takase | e2a582d5fd | |
Takase | 3c60c1c7f1 | |
Guldoman | 532d3a6572 | |
Takase | 7f75619aa2 | |
Guldoman | 0be18493a9 | |
Takase | 6ad288aa39 | |
Takase | c2357721e5 | |
Jefferson González | baa8f528f1 | |
sammyette | 2978037f51 | |
vqn | 7aa1217878 | |
Guldoman | 0ee346014e | |
Takase | 4e626bc320 | |
Takase | c133c39e92 | |
Takase | ac9ca96698 | |
Takase | 26ff5e28a6 | |
Jan | 662fde364b | |
Takase | bc2c433b00 | |
Takase | e935454992 | |
Adam | 7ca0ec18ca | |
vqn | 449f7d66c3 | |
vqn | 46ea86e28c | |
Adam | ee80b451c6 | |
Guldoman | 1c8c569fae | |
Adam | 1becf35508 | |
Guldoman | b005454652 | |
Adam Harrison | 73ff025552 | |
Adam | 7f0651155d | |
Guldoman | 146dca9188 | |
Takase | 350131dabc | |
Guldoman | 1d86665b6d | |
Guldoman | 3739bf0186 | |
Guldoman | 4f1360a6c5 | |
Guldoman | 7907fa785c | |
Takase | 193871869d | |
Guldoman | dbb9f30c81 | |
Takase | 2d2d715fd9 | |
Guldoman | e1f92683bc | |
Adam | 83c27cf9f4 | |
vqn | 9b4a86f763 | |
Adam | b9cc661a84 | |
Guldoman | 7e0ddf2817 | |
jgmdev | 51ab72f715 | |
Eric Gaudet | 911eb325cc | |
Guldoman | d9925b7d44 | |
Guldoman | be5d23557d | |
Jefferson González | ce9d540e92 | |
Jefferson González | 84039331a5 | |
Jefferson González | 1c2571bad7 | |
Jefferson González | d68583b688 | |
Guldoman | 57cd4e2949 | |
Takase | ab3d6004a1 | |
vqn | b634b61866 | |
Himura Kazuto | aef400bc90 | |
sammyette | 3f917dcb45 | |
Adam | 4ef4b99c7a | |
Adam | f74716b436 | |
jgmdev | 8fbc843260 | |
Jefferson González | ccceb2a65c | |
Jan | 16182d01d8 | |
Adam Harrison | de06dcc5bb | |
Jefferson González | 9dcdf1f7c9 | |
Adam | 4682092b8d | |
Guldoman | 12bae1ec95 | |
Jan | 64065b98ca | |
Adam Harrison | bdd87298d6 | |
Guldoman | b58ba3fede | |
xwii | e4c5fceaf9 | |
Merlin Volkmer | 75b6173dc9 | |
adityaraj | 8c4f093c41 | |
Jan | c44a3cd291 | |
Takase | 3edd53a835 |
|
@ -30,9 +30,9 @@ jobs:
|
|||
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
||||
echo "INSTALL_REF=${GITHUB_REF##*/}" >> "$GITHUB_ENV"
|
||||
echo "INSTALL_NAME=lite-xl-${GITHUB_REF##*/}-linux-$(uname -m)-portable" >> "$GITHUB_ENV"
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Python Setup
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.9
|
||||
- name: Update Packages
|
||||
|
@ -47,18 +47,21 @@ jobs:
|
|||
if: ${{ matrix.config.cc == 'gcc' }}
|
||||
run: bash scripts/package.sh --version ${INSTALL_REF} --debug --binary
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
if: ${{ matrix.config.cc == 'gcc' }}
|
||||
with:
|
||||
name: Linux Artifacts
|
||||
path: ${{ env.INSTALL_NAME }}.tar.gz
|
||||
|
||||
build_macos:
|
||||
name: macOS (x86_64)
|
||||
name: macOS
|
||||
runs-on: macos-11
|
||||
env:
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
strategy:
|
||||
matrix:
|
||||
arch: ['x86_64', 'arm64']
|
||||
steps:
|
||||
- name: System Information
|
||||
run: |
|
||||
|
@ -70,24 +73,64 @@ jobs:
|
|||
run: |
|
||||
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
||||
echo "INSTALL_REF=${GITHUB_REF##*/}" >> "$GITHUB_ENV"
|
||||
echo "INSTALL_NAME=lite-xl-${GITHUB_REF##*/}-macos-$(uname -m)" >> "$GITHUB_ENV"
|
||||
- uses: actions/checkout@v2
|
||||
echo "INSTALL_NAME=lite-xl-${GITHUB_REF##*/}-macos-${{ matrix.arch }}" >> "$GITHUB_ENV"
|
||||
if [[ $(uname -m) != ${{ matrix.arch }} ]]; then echo "ARCH=--cross-arch ${{ matrix.arch }}" >> "$GITHUB_ENV"; fi
|
||||
- uses: actions/checkout@v3
|
||||
- name: Python Setup
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.9
|
||||
- name: Install Dependencies
|
||||
run: bash scripts/install-dependencies.sh --debug
|
||||
# --lhelper will eliminate a warning with arm64 and libusb
|
||||
run: bash scripts/install-dependencies.sh --debug --lhelper
|
||||
- name: Build
|
||||
run: |
|
||||
bash --version
|
||||
bash scripts/build.sh --bundle --debug --forcefallback
|
||||
bash scripts/build.sh --bundle --debug --forcefallback $ARCH
|
||||
- name: Create DMG Image
|
||||
run: bash scripts/package.sh --version ${INSTALL_REF} --debug --dmg
|
||||
run: bash scripts/package.sh --version ${INSTALL_REF} $ARCH --debug --dmg
|
||||
- name: Upload DMG Image
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: macOS DMG Image
|
||||
name: macOS DMG Images
|
||||
path: ${{ env.INSTALL_NAME }}.dmg
|
||||
|
||||
build_macos_universal:
|
||||
name: macOS (Universal)
|
||||
runs-on: macos-11
|
||||
needs: build_macos
|
||||
steps:
|
||||
- name: System Information
|
||||
run: |
|
||||
system_profiler SPSoftwareDataType
|
||||
bash --version
|
||||
gcc -v
|
||||
xcodebuild -version
|
||||
- name: Set Environment Variables
|
||||
run: |
|
||||
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
||||
echo "INSTALL_NAME=lite-xl-${GITHUB_REF##*/}-macos-universal" >> "$GITHUB_ENV"
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.9'
|
||||
- name: Install dmgbuild
|
||||
run: pip install dmgbuild
|
||||
- uses: actions/checkout@v3
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
id: download
|
||||
with:
|
||||
name: macOS DMG Images
|
||||
path: dmgs-original
|
||||
- name: Make universal bundles
|
||||
run: |
|
||||
bash --version
|
||||
bash scripts/make-universal-binaries.sh ${{ steps.download.outputs.download-path }} "${INSTALL_NAME}"
|
||||
- name: Upload DMG Image
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: macOS Universal DMG Images
|
||||
path: ${{ env.INSTALL_NAME }}.dmg
|
||||
|
||||
build_windows_msys2:
|
||||
|
@ -95,20 +138,26 @@ jobs:
|
|||
runs-on: windows-2019
|
||||
strategy:
|
||||
matrix:
|
||||
msystem: [MINGW32, MINGW64]
|
||||
config:
|
||||
- {msystem: MINGW32, arch: i686}
|
||||
- {msystem: MINGW64, arch: x86_64}
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: ${{ matrix.msystem }}
|
||||
update: true
|
||||
msystem: ${{ matrix.config.msystem }}
|
||||
install: >-
|
||||
base-devel
|
||||
git
|
||||
zip
|
||||
mingw-w64-${{ matrix.config.arch }}-gcc
|
||||
mingw-w64-${{ matrix.config.arch }}-meson
|
||||
mingw-w64-${{ matrix.config.arch }}-ninja
|
||||
mingw-w64-${{ matrix.config.arch }}-ca-certificates
|
||||
mingw-w64-${{ matrix.config.arch }}-ntldd
|
||||
- name: Set Environment Variables
|
||||
run: |
|
||||
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
||||
|
@ -119,6 +168,7 @@ jobs:
|
|||
echo "INSTALL_NAME=lite-xl-${GITHUB_REF##*/}-windows-i686" >> "$GITHUB_ENV"
|
||||
fi
|
||||
- name: Install Dependencies
|
||||
if: false
|
||||
run: bash scripts/install-dependencies.sh --debug
|
||||
- name: Build
|
||||
run: |
|
||||
|
@ -127,7 +177,7 @@ jobs:
|
|||
- name: Package
|
||||
run: bash scripts/package.sh --version ${INSTALL_REF} --debug --binary
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Windows Artifacts
|
||||
path: ${{ env.INSTALL_NAME }}.zip
|
||||
|
@ -137,34 +187,41 @@ jobs:
|
|||
runs-on: windows-2019
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, amd64_x86]
|
||||
arch:
|
||||
- { target: x86, name: i686 }
|
||||
- { target: x64, name: x86_64 }
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: ${{ matrix.arch }}
|
||||
- uses: actions/setup-python@v1
|
||||
arch: ${{ matrix.arch.target }}
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install meson and ninja
|
||||
run: pip install meson ninja
|
||||
- name: Set up environment variables
|
||||
run: |
|
||||
"INSTALL_NAME=lite-xl-$($env:GITHUB_REF -replace ".*/")-windows-msvc-${{ matrix.arch }}" >> $env:GITHUB_ENV
|
||||
"INSTALL_NAME=lite-xl-$($env:GITHUB_REF -replace ".*/")-windows-msvc-${{ matrix.arch.name }}" >> $env:GITHUB_ENV
|
||||
"INSTALL_REF=$($env:GITHUB_REF -replace ".*/")" >> $env:GITHUB_ENV
|
||||
"LUA_SUBPROJECT_PATH=subprojects/lua-5.4.4" >> $env:GITHUB_ENV
|
||||
"LUA_SUBPROJECT_PATH=subprojects/$(awk -F ' *= *' '/directory/ { printf $2 }' subprojects/lua.wrap)" >> $env:GITHUB_ENV
|
||||
- name: Download and patch subprojects
|
||||
shell: bash
|
||||
run: |
|
||||
meson subprojects download
|
||||
cat resources/windows/001-lua-unicode.diff | patch -Np1 -d "$LUA_SUBPROJECT_PATH"
|
||||
- name: Configure
|
||||
run: |
|
||||
meson setup --wrap-mode=forcefallback build
|
||||
Get-Content -Path resources/windows/001-lua-unicode.diff -Raw | patch -d $env:LUA_SUBPROJECT_PATH -p1 --forward
|
||||
- name: Build
|
||||
run: meson install -C build --destdir="../lite-xl"
|
||||
run: |
|
||||
meson install -C build --destdir="../lite-xl"
|
||||
- name: Package
|
||||
run: |
|
||||
Remove-Item -Recurse -Force -Path "lite-xl/lib","lite-xl/include"
|
||||
Compress-Archive -Path lite-xl -DestinationPath "$env:INSTALL_NAME.zip"
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Windows Artifacts (MSVC)
|
||||
path: ${{ env.INSTALL_NAME }}.zip
|
||||
|
|
|
@ -9,19 +9,21 @@ on:
|
|||
inputs:
|
||||
version:
|
||||
description: Release Version
|
||||
default: v2.1.1
|
||||
default: v2.1.4
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
outputs:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
version: ${{ steps.tag.outputs.version }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
- name: Fetch Version
|
||||
id: tag
|
||||
run: |
|
||||
|
@ -49,7 +51,8 @@ jobs:
|
|||
build_linux:
|
||||
name: Linux
|
||||
needs: release
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/lite-xl/lite-xl-build-box:latest
|
||||
env:
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
|
@ -58,17 +61,27 @@ jobs:
|
|||
run: |
|
||||
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
||||
echo "INSTALL_REF=${{ needs.release.outputs.version }}" >> "$GITHUB_ENV"
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
# disabled because this will break our own Python install
|
||||
- name: Python Setup
|
||||
uses: actions/setup-python@v2
|
||||
if: false
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.9
|
||||
|
||||
# disabled because the container has up-to-date packages
|
||||
- name: Update Packages
|
||||
if: false
|
||||
run: sudo apt-get update
|
||||
|
||||
# disabled as the dependencies are already installed
|
||||
- name: Install Dependencies
|
||||
if: false
|
||||
run: |
|
||||
bash scripts/install-dependencies.sh --debug
|
||||
sudo apt-get install -y ccache
|
||||
|
||||
- name: Build Portable
|
||||
run: |
|
||||
bash --version
|
||||
|
@ -93,7 +106,7 @@ jobs:
|
|||
LiteXL-${{ env.INSTALL_REF }}-addons-x86_64.AppImage
|
||||
|
||||
build_macos:
|
||||
name: macOS (x86_64)
|
||||
name: macOS
|
||||
needs: release
|
||||
runs-on: macos-11
|
||||
strategy:
|
||||
|
@ -115,9 +128,10 @@ jobs:
|
|||
echo "INSTALL_REF=${{ needs.release.outputs.version }}" >> "$GITHUB_ENV"
|
||||
echo "INSTALL_NAME=lite-xl-${{ needs.release.outputs.version }}-macos-${{ matrix.arch }}" >> "$GITHUB_ENV"
|
||||
echo "INSTALL_NAME_ADDONS=lite-xl-${{ needs.release.outputs.version }}-addons-macos-${{ matrix.arch }}" >> "$GITHUB_ENV"
|
||||
- uses: actions/checkout@v2
|
||||
if [[ $(uname -m) != ${{ matrix.arch }} ]]; then echo "ARCH=--cross-arch ${{ matrix.arch }}" >> "$GITHUB_ENV"; fi
|
||||
- uses: actions/checkout@v3
|
||||
- name: Python Setup
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.9
|
||||
- name: Install Dependencies
|
||||
|
@ -125,11 +139,18 @@ jobs:
|
|||
- name: Build
|
||||
run: |
|
||||
bash --version
|
||||
CROSS_ARCH=${{ matrix.arch }} bash scripts/build.sh --bundle --debug --forcefallback --release
|
||||
bash scripts/build.sh --bundle --debug --forcefallback --release $ARCH
|
||||
- name: Create DMG Image
|
||||
run: |
|
||||
CROSS_ARCH=${{ matrix.arch }} bash scripts/package.sh --version ${INSTALL_REF} --debug --dmg --release
|
||||
CROSS_ARCH=${{ matrix.arch }} bash scripts/package.sh --version ${INSTALL_REF} --debug --addons --dmg --release
|
||||
bash scripts/package.sh --version ${INSTALL_REF} $ARCH --debug --dmg --release
|
||||
bash scripts/package.sh --version ${INSTALL_REF} $ARCH --debug --addons --dmg --release
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: macOS DMG Images
|
||||
path: |
|
||||
${{ env.INSTALL_NAME }}.dmg
|
||||
${{ env.INSTALL_NAME_ADDONS }}.dmg
|
||||
- name: Upload Files
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
|
@ -139,6 +160,54 @@ jobs:
|
|||
${{ env.INSTALL_NAME }}.dmg
|
||||
${{ env.INSTALL_NAME_ADDONS }}.dmg
|
||||
|
||||
build_macos_universal:
|
||||
name: macOS (Universal)
|
||||
needs: [release, build_macos]
|
||||
runs-on: macos-11
|
||||
steps:
|
||||
- name: System Information
|
||||
run: |
|
||||
system_profiler SPSoftwareDataType
|
||||
bash --version
|
||||
gcc -v
|
||||
xcodebuild -version
|
||||
- name: Set Environment Variables
|
||||
run: |
|
||||
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
||||
echo "INSTALL_BASE=lite-xl-${{ needs.release.outputs.version }}-macos" >> "$GITHUB_ENV"
|
||||
echo "INSTALL_BASE_ADDONS=lite-xl-${{ needs.release.outputs.version }}-addons-macos" >> "$GITHUB_ENV"
|
||||
- uses: actions/checkout@v2
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
id: download
|
||||
with:
|
||||
name: macOS DMG Images
|
||||
path: dmgs-original
|
||||
- name: Python Setup
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.9
|
||||
- name: Install dmgbuild
|
||||
run: pip install dmgbuild
|
||||
- name: Prepare DMG Images
|
||||
run: |
|
||||
mkdir -p dmgs-addons dmgs-normal
|
||||
mv -v "${{ steps.download.outputs.download-path }}/$INSTALL_BASE-"{x86_64,arm64}.dmg dmgs-normal
|
||||
mv -v "${{ steps.download.outputs.download-path }}/$INSTALL_BASE_ADDONS-"{x86_64,arm64}.dmg dmgs-addons
|
||||
- name: Create Universal DMGs
|
||||
run: |
|
||||
bash --version
|
||||
bash scripts/make-universal-binaries.sh dmgs-normal "$INSTALL_BASE-universal"
|
||||
bash scripts/make-universal-binaries.sh dmgs-addons "$INSTALL_BASE_ADDONS-universal"
|
||||
- name: Upload Files
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: ${{ needs.release.outputs.version }}
|
||||
draft: true
|
||||
files: |
|
||||
${{ env.INSTALL_BASE }}-universal.dmg
|
||||
${{ env.INSTALL_BASE_ADDONS }}-universal.dmg
|
||||
|
||||
build_windows_msys2:
|
||||
name: Windows
|
||||
needs: release
|
||||
|
@ -150,7 +219,7 @@ jobs:
|
|||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: ${{ matrix.msystem }}
|
||||
|
|
|
@ -22,9 +22,10 @@ LiteXL*
|
|||
lite
|
||||
.config/
|
||||
*.lha
|
||||
release_files
|
||||
*.o
|
||||
*.snalyzerinfo
|
||||
|
||||
|
||||
!resources/windows/*.diff
|
||||
!resources/windows/*.exe.manifest.in
|
||||
!resources/macos/*.py
|
||||
|
|
4
LICENSE
4
LICENSE
|
@ -1,4 +1,6 @@
|
|||
Copyright (c) 2020-2021 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
|
||||
|
|
36
Makefile.mos
36
Makefile.mos
|
@ -9,18 +9,22 @@ LiteXL_OBJ := \
|
|||
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/api/dirmonitor/mos.o src/platform/codesets.o
|
||||
|
||||
outfile := lite-xl
|
||||
compiler := gcc
|
||||
cxxcompiler := g++
|
||||
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 -lSDL2 -llua54 -lagg -lfreetype -lm -lc -L/usr/local/lib
|
||||
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
|
||||
|
||||
|
@ -32,14 +36,14 @@ clean:
|
|||
|
||||
LiteXL: $(LiteXL_OBJ)
|
||||
@echo "Linking LiteXL"
|
||||
@$(cxxcompiler) -o $(outfile) $(LiteXL_OBJ) $(LFLAGS)
|
||||
$(compiler) -o $(outfile) $(LiteXL_OBJ) $(LFLAGS)
|
||||
|
||||
.c.o:
|
||||
@echo "Compiling $<"
|
||||
@$(compiler) -c $< -o $*.o $(CFLAGS) $(INCPATH) $(DFLAGS)
|
||||
$(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/renderer.h src/platform/morphos.h src/platform/codesets.h
|
||||
|
||||
src/rencache.o: src/rencache.c
|
||||
|
||||
|
@ -53,7 +57,7 @@ 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/api/system.o: src/api/system.c src/platform/morphos.h
|
||||
|
||||
src/platform/morphos.o: src/platform/morphos.c
|
||||
|
||||
|
@ -63,18 +67,22 @@ 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 release_files/* release/LiteXL2/ -r
|
||||
@cp -r resources/amiga/* release/LiteXL2/
|
||||
@mv release/LiteXL2/LiteXL2.info release/
|
||||
@cp data release/LiteXL2/ -r
|
||||
@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..."
|
||||
|
|
26
Makefile.os4
26
Makefile.os4
|
@ -9,21 +9,19 @@ LiteXL_OBJ := \
|
|||
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/api/dirmonitor/os4.o src/platform/codesets.o
|
||||
|
||||
outfile := lite-xl
|
||||
compiler := gcc-11
|
||||
cxxcompiler := g++-11
|
||||
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 -lauto \
|
||||
-lpcre2 -lSDL2 -llua54 -lfreetype -lz -lm -lpthread -athread=native
|
||||
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
|
||||
|
@ -56,7 +54,7 @@ LiteXL: $(LiteXL_OBJ)
|
|||
|
||||
|
||||
src/main.o: src/main.c src/api/api.h src/rencache.h \
|
||||
src/renderer.h src/platform/amigaos4.h
|
||||
src/renderer.h src/platform/amigaos4.h src/platform/codesets.h
|
||||
|
||||
src/rencache.o: src/rencache.c
|
||||
|
||||
|
@ -70,13 +68,15 @@ 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/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/api/utf8.o: src/api/utf8.c src/platform/amigaos4.h
|
||||
|
||||
src/api/dirmonitor/os4.o: src/api/dirmonitor/os4.c
|
||||
|
||||
|
@ -85,8 +85,9 @@ src/api/process.o: src/api/process.c
|
|||
release: clean LiteXL
|
||||
@echo "Creating release files..."
|
||||
@mkdir -p release/LiteXL2
|
||||
@cp -r release_files/* 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/
|
||||
|
@ -94,6 +95,7 @@ release: clean LiteXL
|
|||
@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..."
|
||||
|
|
39
README.md
39
README.md
|
@ -81,6 +81,39 @@ affects only the place where the application is actually installed.
|
|||
|
||||
Head over to [releases](https://github.com/lite-xl/lite-xl/releases) and download the version for your operating system.
|
||||
|
||||
### Windows
|
||||
|
||||
Lite XL comes with installers on Windows for typical installations.
|
||||
Alternatively, we provide ZIP archives that you can download and extract anywhere and run directly.
|
||||
|
||||
To make Lite XL portable (e.g. running Lite XL from a thumb drive),
|
||||
simply create a `user` folder where `lite-xl.exe` is located.
|
||||
Lite XL will load and store all your configurations and plugins in the folder.
|
||||
|
||||
### macOS
|
||||
|
||||
We provide DMG files for macOS. Simply drag the program into your Applications folder.
|
||||
|
||||
> **Important**
|
||||
> Newer versions of Lite XL are signed with a self-signed certificate,
|
||||
> so you'll have to follow these steps when running Lite XL for the first time.
|
||||
>
|
||||
> 1. Find Lite XL in Finder (do not open it in Launchpad).
|
||||
> 2. Control-click Lite XL, then choose `Open` from the shortcut menu.
|
||||
> 3. Click `Open` in the popup menu.
|
||||
>
|
||||
> The correct steps may vary between macOS versions, so you should refer to
|
||||
> the [macOS User Guide](https://support.apple.com/en-my/guide/mac-help/mh40616/mac).
|
||||
>
|
||||
> On an older version of Lite XL, you will need to run these commands instead:
|
||||
>
|
||||
> ```sh
|
||||
> # clears attributes from the directory
|
||||
> xattr -cr /Applications/Lite\ XL.app
|
||||
> ```
|
||||
>
|
||||
> Otherwise, macOS will display a **very misleading error** saying that the application is damaged.
|
||||
|
||||
### Linux
|
||||
|
||||
Unzip the file and `cd` into the `lite-xl` directory:
|
||||
|
@ -92,15 +125,15 @@ cd lite-xl
|
|||
|
||||
To run lite-xl without installing:
|
||||
```sh
|
||||
cd bin
|
||||
./lite-xl
|
||||
```
|
||||
|
||||
To install lite-xl copy files over into appropriate directories:
|
||||
|
||||
```sh
|
||||
mkdir -p $HOME/.local/bin && cp bin/lite-xl $HOME/.local/bin
|
||||
cp -r share $HOME/.local
|
||||
rm -rf $HOME/.local/share/lite-xl $HOME/.local/bin/lite-xl
|
||||
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/
|
||||
```
|
||||
|
||||
If `$HOME/.local/bin` is not in PATH:
|
||||
|
|
|
@ -87,6 +87,15 @@ 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.
|
||||
|
@ -107,7 +116,10 @@ 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.
|
||||
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
|
||||
|
@ -166,6 +178,9 @@ 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
|
||||
|
||||
|
@ -215,6 +230,60 @@ https://git.walkero.gr/walkero/lite-xl/issues
|
|||
|
||||
# Changelog
|
||||
|
||||
## [2.1.4r1] - 2024-05-23
|
||||
### Added
|
||||
- Added the ability to open files and folders by drag 'n drop them on the
|
||||
LiteXL icon when this is on the AmiDock (AmigaOS4) / Panel (MorphOS)
|
||||
|
||||
### 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
|
||||
|
|
|
@ -18,6 +18,8 @@ show_help() {
|
|||
echo " Default: '$(get_default_build_dir)'."
|
||||
echo "-p --prefix PREFIX Install directory prefix."
|
||||
echo " Default: '/'."
|
||||
echo " --cross-platform PLATFORM The platform to cross compile for."
|
||||
echo " --cross-arch ARCH The architecture to cross compile for."
|
||||
echo " --debug Debug this script."
|
||||
echo
|
||||
echo "Build options:"
|
||||
|
@ -27,6 +29,7 @@ show_help() {
|
|||
echo "-P --portable Create a portable package."
|
||||
echo "-O --pgo Use profile guided optimizations (pgo)."
|
||||
echo " Requires running the application iteractively."
|
||||
echo " --cross-file CROSS_FILE The cross file used for compiling."
|
||||
echo
|
||||
echo "Package options:"
|
||||
echo
|
||||
|
@ -35,7 +38,7 @@ show_help() {
|
|||
echo "-v --version VERSION Sets the version on the package name."
|
||||
echo "-A --appimage Create an AppImage (Linux only)."
|
||||
echo "-D --dmg Create a DMG disk image (macOS only)."
|
||||
echo " Requires NPM and AppDMG."
|
||||
echo " Requires dmgbuild."
|
||||
echo "-I --innosetup Create an InnoSetup installer (Windows only)."
|
||||
echo "-r --release Compile in release mode."
|
||||
echo "-S --source Create a source code package,"
|
||||
|
@ -60,6 +63,12 @@ main() {
|
|||
local portable
|
||||
local pgo
|
||||
local release
|
||||
local cross_platform
|
||||
local cross_platform_option=()
|
||||
local cross_arch
|
||||
local cross_arch_option=()
|
||||
local cross_file
|
||||
local cross_file_option=()
|
||||
|
||||
for i in "$@"; do
|
||||
case $i in
|
||||
|
@ -123,6 +132,21 @@ main() {
|
|||
pgo="--pgo"
|
||||
shift
|
||||
;;
|
||||
--cross-platform)
|
||||
cross_platform="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
--cross-arch)
|
||||
cross_arch="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
--cross-file)
|
||||
cross_file="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
--debug)
|
||||
debug="--debug"
|
||||
set -x
|
||||
|
@ -143,10 +167,18 @@ main() {
|
|||
if [[ -n $dest_dir ]]; then dest_dir_option=("--destdir" "${dest_dir}"); fi
|
||||
if [[ -n $prefix ]]; then prefix_option=("--prefix" "${prefix}"); fi
|
||||
if [[ -n $version ]]; then version_option=("--version" "${version}"); fi
|
||||
if [[ -n $cross_platform ]]; then cross_platform_option=("--cross-platform" "${cross_platform}"); fi
|
||||
if [[ -n $cross_arch ]]; then cross_arch_option=("--cross-arch" "${cross_arch}"); fi
|
||||
if [[ -n $cross_file ]]; then cross_file_option=("--cross-file" "${cross_file}"); fi
|
||||
|
||||
|
||||
|
||||
source scripts/build.sh \
|
||||
${build_dir_option[@]} \
|
||||
${prefix_option[@]} \
|
||||
${cross_platform_option[@]} \
|
||||
${cross_arch_option[@]} \
|
||||
${cross_file_option[@]} \
|
||||
$debug \
|
||||
$force_fallback \
|
||||
$bundle \
|
||||
|
@ -159,6 +191,8 @@ main() {
|
|||
${dest_dir_option[@]} \
|
||||
${prefix_option[@]} \
|
||||
${version_option[@]} \
|
||||
${cross_platform_option[@]} \
|
||||
${cross_arch_option[@]} \
|
||||
--binary \
|
||||
--addons \
|
||||
$debug \
|
||||
|
|
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
|
||||
|
|
|
@ -1,25 +1,55 @@
|
|||
local core = require "core"
|
||||
local command = {}
|
||||
|
||||
---A predicate function accepts arguments from `command.perform()` and evaluates to a boolean. </br>
|
||||
---If the function returns true, then the function associated with the command is executed.
|
||||
---
|
||||
---The predicate function can also return other values after the boolean, which will
|
||||
---be passed into the function associated with the command.
|
||||
---@alias core.command.predicate_function fun(...: any): boolean, ...
|
||||
|
||||
---A predicate is a string, an Object or a function, that is used to determine
|
||||
---whether a command should be executed.
|
||||
---
|
||||
---If the predicate is a string, it is resolved into an `Object` via `require()`
|
||||
---and checked against the active view with `Object:extends()`. </br>
|
||||
---For example, `"core.docview"` will match any view that inherits from `DocView`. </br>
|
||||
---A `!` can be appended to the predicate to strictly match the current view via `Object:is()`,
|
||||
---instead of matching any view that inherits the predicate.
|
||||
---
|
||||
---If the predicate is a table, it is checked against the active view with `Object:extends()`.
|
||||
---Strict matching via `Object:is()` is not available.
|
||||
---
|
||||
---If the predicate is a function, it must behave like a predicate function.
|
||||
---@see core.command.predicate_function
|
||||
---@alias core.command.predicate string|core.object|core.command.predicate_function
|
||||
|
||||
---A command is identified by a command name.
|
||||
---The command name contains a category and the name itself, separated by a colon (':').
|
||||
---
|
||||
---All commands should be in lowercase and should not contain whitespaces; instead
|
||||
---they should be replaced by a dash ('-').
|
||||
---@alias core.command.command_name string
|
||||
|
||||
---The predicate and its associated function.
|
||||
---@class core.command.command
|
||||
---@field predicate core.command.predicate_function
|
||||
---@field perform fun(...: any)
|
||||
|
||||
---@type { [string]: core.command.command }
|
||||
command.map = {}
|
||||
|
||||
---@type core.command.predicate_function
|
||||
local always_true = function() return true end
|
||||
|
||||
|
||||
---Used iternally by command.add, statusview, and contextmenu to generate a
|
||||
---function with a condition to evaluate returning the boolean result of this
|
||||
---evaluation.
|
||||
---This function takes in a predicate and produces a predicate function
|
||||
---that is internally used to dispatch and execute commands.
|
||||
---
|
||||
---If a string predicate is given it is treated as a require import that should
|
||||
---return a valid object which is checked against the current active view,
|
||||
---eg: "core.docview" will match any view that inherits from DocView. Appending
|
||||
---a `!` at the end of the string means we want to match the given object
|
||||
---from the import strcitly eg: "core.docview!" only DocView is matched.
|
||||
---A function that returns a boolean can be used instead to perform a custom
|
||||
---evaluation, setting to nil means always evaluates to true.
|
||||
---
|
||||
---@param predicate string | table | function
|
||||
---@return function
|
||||
---This function should not be called manually.
|
||||
---@see core.command.predicate
|
||||
---@param predicate core.command.predicate|nil If nil, the predicate always evaluates to true.
|
||||
---@return core.command.predicate_function
|
||||
function command.generate_predicate(predicate)
|
||||
predicate = predicate or always_true
|
||||
local strict = false
|
||||
|
@ -38,10 +68,20 @@ function command.generate_predicate(predicate)
|
|||
predicate = function(...) return core.active_view:is(class), core.active_view, ... end
|
||||
end
|
||||
end
|
||||
---@cast predicate core.command.predicate_function
|
||||
return predicate
|
||||
end
|
||||
|
||||
|
||||
---Adds commands to the map.
|
||||
---
|
||||
---The function accepts a table containing a list of commands
|
||||
---and their functions. </br>
|
||||
---If a command already exists, it will be replaced.
|
||||
---@see core.command.predicate
|
||||
---@see core.command.command_name
|
||||
---@param predicate core.command.predicate
|
||||
---@param map { [core.command.command_name]: fun(...: any) }
|
||||
function command.add(predicate, map)
|
||||
predicate = command.generate_predicate(predicate)
|
||||
for name, fn in pairs(map) do
|
||||
|
@ -57,11 +97,21 @@ local function capitalize_first(str)
|
|||
return str:sub(1, 1):upper() .. str:sub(2)
|
||||
end
|
||||
|
||||
---Prettifies the command name.
|
||||
---
|
||||
---This function adds a space between the colon and the command name,
|
||||
---replaces dashes with spaces and capitalizes the command appropriately.
|
||||
---@see core.command.command_name
|
||||
---@param name core.command.command_name
|
||||
---@return string
|
||||
function command.prettify_name(name)
|
||||
---@diagnostic disable-next-line: redundant-return-value
|
||||
return name:gsub(":", ": "):gsub("-", " "):gsub("%S+", capitalize_first)
|
||||
end
|
||||
|
||||
|
||||
---Returns all the commands that can be executed (their predicates evaluate to true).
|
||||
---@return core.command.command_name[]
|
||||
function command.get_all_valid()
|
||||
local res = {}
|
||||
local memoized_predicates = {}
|
||||
|
@ -76,6 +126,10 @@ function command.get_all_valid()
|
|||
return res
|
||||
end
|
||||
|
||||
---Checks whether a command can be executed (its predicate evaluates to true).
|
||||
---@param name core.command.command_name
|
||||
---@param ... any
|
||||
---@return boolean
|
||||
function command.is_valid(name, ...)
|
||||
return command.map[name] and command.map[name].predicate(...)
|
||||
end
|
||||
|
@ -98,16 +152,30 @@ local function perform(name, ...)
|
|||
end
|
||||
|
||||
|
||||
function command.perform(...)
|
||||
local ok, res = core.try(perform, ...)
|
||||
---Performs a command.
|
||||
---
|
||||
---The arguments passed into this function are forwarded to the predicate function. </br>
|
||||
---If the predicate function returns more than 1 value, the other values are passed
|
||||
---to the command.
|
||||
---
|
||||
---Otherwise, the arguments passed into this function are passed directly
|
||||
---to the command.
|
||||
---@see core.command.predicate
|
||||
---@see core.command.predicate_function
|
||||
---@param name core.command.command_name
|
||||
---@param ... any
|
||||
---@return boolean # true if the command is performed successfully.
|
||||
function command.perform(name, ...)
|
||||
local ok, res = core.try(perform, name, ...)
|
||||
return not ok or res
|
||||
end
|
||||
|
||||
|
||||
---Inserts the default commands for Lite XL into the map.
|
||||
function command.add_defaults()
|
||||
local reg = {
|
||||
"core", "root", "command", "doc", "findreplace",
|
||||
"files", "drawwhitespace", "dialog", "log", "statusbar"
|
||||
"files", "dialog", "log", "statusbar"
|
||||
}
|
||||
for _, name in ipairs(reg) do
|
||||
require("core.commands." .. name)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -43,9 +43,9 @@ local function save(filename)
|
|||
core.log("Saved \"%s\"", saved_filename)
|
||||
else
|
||||
core.error(err)
|
||||
core.nag_view:show("Saving failed", string.format("Could not save \"%s\" do you want to save to another location?", doc().filename), {
|
||||
{ font = style.font, text = "No", default_no = true },
|
||||
{ font = style.font, text = "Yes" , default_yes = true }
|
||||
core.nag_view:show("Saving failed", string.format("Couldn't save file \"%s\". Do you want to save to another location?", doc().filename), {
|
||||
{ text = "Yes", default_yes = true },
|
||||
{ text = "No", default_no = true }
|
||||
}, function(item)
|
||||
if item.text == "Yes" then
|
||||
core.add_thread(function()
|
||||
|
@ -62,10 +62,10 @@ local function cut_or_copy(delete)
|
|||
local text = ""
|
||||
core.cursor_clipboard = {}
|
||||
core.cursor_clipboard_whole_line = {}
|
||||
for idx, line1, col1, line2, col2 in doc():get_selections() do
|
||||
for idx, line1, col1, line2, col2 in doc():get_selections(true, true) do
|
||||
if line1 ~= line2 or col1 ~= col2 then
|
||||
text = doc():get_text(line1, col1, line2, col2)
|
||||
full_text = full_text == "" and text or (full_text .. " " .. text)
|
||||
full_text = full_text == "" and text or (text .. " " .. full_text)
|
||||
core.cursor_clipboard_whole_line[idx] = false
|
||||
if delete then
|
||||
doc():delete_to_cursor(idx, 0)
|
||||
|
@ -73,7 +73,7 @@ local function cut_or_copy(delete)
|
|||
else -- Cut/copy whole line
|
||||
-- Remove newline from the text. It will be added as needed on paste.
|
||||
text = string.sub(doc().lines[line1], 1, -2)
|
||||
full_text = full_text == "" and text or (full_text .. text .. "\n")
|
||||
full_text = full_text == "" and text .. "\n" or (text .. "\n" .. full_text)
|
||||
core.cursor_clipboard_whole_line[idx] = true
|
||||
if delete then
|
||||
if line1 < #doc().lines then
|
||||
|
@ -83,19 +83,24 @@ local function cut_or_copy(delete)
|
|||
else
|
||||
doc():remove(line1 - 1, math.huge, line1, math.huge)
|
||||
end
|
||||
doc():set_selections(idx, line1, col1, line2, col2)
|
||||
end
|
||||
end
|
||||
core.cursor_clipboard[idx] = text
|
||||
end
|
||||
if delete then doc():merge_cursors() end
|
||||
core.cursor_clipboard["full"] = full_text
|
||||
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
|
||||
|
@ -105,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
|
||||
|
@ -323,7 +328,7 @@ local commands = {
|
|||
end,
|
||||
|
||||
["doc:delete"] = function(dv)
|
||||
for idx, line1, col1, line2, col2 in dv.doc:get_selections() do
|
||||
for idx, line1, col1, line2, col2 in dv.doc:get_selections(true, true) do
|
||||
if line1 == line2 and col1 == col2 and dv.doc.lines[line1]:find("^%s*$", col1) then
|
||||
dv.doc:remove(line1, col1, line1, math.huge)
|
||||
end
|
||||
|
@ -333,15 +338,16 @@ local commands = {
|
|||
|
||||
["doc:backspace"] = function(dv)
|
||||
local _, indent_size = dv.doc:get_indent_info()
|
||||
for idx, line1, col1, line2, col2 in dv.doc:get_selections() do
|
||||
for idx, line1, col1, line2, col2 in dv.doc:get_selections(true, true) do
|
||||
if line1 == line2 and col1 == col2 then
|
||||
local text = dv.doc:get_text(line1, 1, line1, col1)
|
||||
if #text >= indent_size and text:find("^ *$") then
|
||||
dv.doc:delete_to_cursor(idx, 0, -indent_size)
|
||||
return
|
||||
goto continue
|
||||
end
|
||||
end
|
||||
dv.doc:delete_to_cursor(idx, translate.previous_char)
|
||||
::continue::
|
||||
end
|
||||
end,
|
||||
|
||||
|
@ -618,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
|
||||
|
||||
|
@ -698,6 +704,7 @@ commands["doc:move-to-previous-char"] = function(dv)
|
|||
dv.doc:move_to_cursor(idx, translate.previous_char)
|
||||
end
|
||||
end
|
||||
dv.doc:merge_cursors()
|
||||
end
|
||||
|
||||
commands["doc:move-to-next-char"] = function(dv)
|
||||
|
@ -708,6 +715,7 @@ commands["doc:move-to-next-char"] = function(dv)
|
|||
dv.doc:move_to_cursor(idx, translate.next_char)
|
||||
end
|
||||
end
|
||||
dv.doc:merge_cursors()
|
||||
end
|
||||
|
||||
command.add("core.docview", commands)
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
local command = require "core.command"
|
||||
local config = require "core.config"
|
||||
|
||||
command.add(nil, {
|
||||
["draw-whitespace:toggle"] = function()
|
||||
config.draw_whitespace = not config.draw_whitespace
|
||||
end,
|
||||
|
||||
["draw-whitespace:disable"] = function()
|
||||
config.draw_whitespace = false
|
||||
end,
|
||||
|
||||
["draw-whitespace:enable"] = function()
|
||||
config.draw_whitespace = true
|
||||
end,
|
||||
})
|
|
@ -164,13 +164,16 @@ local function is_in_any_selection(line, col)
|
|||
end
|
||||
|
||||
local function select_add_next(all)
|
||||
local il1, ic1 = doc():get_selection(true)
|
||||
for idx, l1, c1, l2, c2 in doc():get_selections(true, true) do
|
||||
local il1, ic1
|
||||
for _, l1, c1, l2, c2 in doc():get_selections(true, true) do
|
||||
if not il1 then
|
||||
il1, ic1 = l1, c1
|
||||
end
|
||||
local text = doc():get_text(l1, c1, l2, c2)
|
||||
repeat
|
||||
l1, c1, l2, c2 = search.find(doc(), l2, c2, text, { wrap = true })
|
||||
if l1 == il1 and c1 == ic1 then break end
|
||||
if l2 and (all or not is_in_any_selection(l2, c2)) then
|
||||
if l2 and not is_in_any_selection(l2, c2) then
|
||||
doc():add_selection(l2, c2, l1, c1)
|
||||
if not all then
|
||||
core.active_view:scroll_to_make_visible(l2, c2)
|
||||
|
@ -240,34 +243,38 @@ command.add("core.docview!", {
|
|||
})
|
||||
|
||||
local function valid_for_finding()
|
||||
return core.active_view:is(DocView) or core.active_view:is(CommandView)
|
||||
-- Allow using this while in the CommandView
|
||||
if core.active_view:is(CommandView) and last_view then
|
||||
return true, last_view
|
||||
end
|
||||
return core.active_view:is(DocView), core.active_view
|
||||
end
|
||||
|
||||
command.add(valid_for_finding, {
|
||||
["find-replace:repeat-find"] = function()
|
||||
["find-replace:repeat-find"] = function(dv)
|
||||
if not last_fn then
|
||||
core.error("No find to continue from")
|
||||
else
|
||||
local sl1, sc1, sl2, sc2 = doc():get_selection(true)
|
||||
local line1, col1, line2, col2 = last_fn(doc(), sl1, sc2, last_text, case_sensitive, find_regex, false)
|
||||
local sl1, sc1, sl2, sc2 = dv.doc:get_selection(true)
|
||||
local line1, col1, line2, col2 = last_fn(dv.doc, sl2, sc2, last_text, case_sensitive, find_regex, false)
|
||||
if line1 then
|
||||
doc():set_selection(line2, col2, line1, col1)
|
||||
last_view:scroll_to_line(line2, true)
|
||||
dv.doc:set_selection(line2, col2, line1, col1)
|
||||
dv:scroll_to_line(line2, true)
|
||||
else
|
||||
core.error("Couldn't find %q", last_text)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
["find-replace:previous-find"] = function()
|
||||
["find-replace:previous-find"] = function(dv)
|
||||
if not last_fn then
|
||||
core.error("No find to continue from")
|
||||
else
|
||||
local sl1, sc1, sl2, sc2 = doc():get_selection(true)
|
||||
local line1, col1, line2, col2 = last_fn(doc(), sl1, sc1, last_text, case_sensitive, find_regex, true)
|
||||
local sl1, sc1, sl2, sc2 = dv.doc:get_selection(true)
|
||||
local line1, col1, line2, col2 = last_fn(dv.doc, sl1, sc1, last_text, case_sensitive, find_regex, true)
|
||||
if line1 then
|
||||
doc():set_selection(line2, col2, line1, col1)
|
||||
last_view:scroll_to_line(line2, true)
|
||||
dv.doc:set_selection(line2, col2, line1, col1)
|
||||
dv:scroll_to_line(line2, true)
|
||||
else
|
||||
core.error("Couldn't find %q", last_text)
|
||||
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
|
||||
|
@ -123,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)
|
||||
|
@ -146,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
|
||||
|
||||
|
||||
|
@ -256,6 +277,7 @@ function CommandView:update_suggestions()
|
|||
end
|
||||
self.suggestions = res
|
||||
self.suggestion_idx = 1
|
||||
self.suggestions_offset = 1
|
||||
end
|
||||
|
||||
|
||||
|
@ -299,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
|
||||
|
@ -335,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)
|
||||
|
@ -344,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
|
||||
|
|
|
@ -1,21 +1,41 @@
|
|||
local common = {}
|
||||
|
||||
|
||||
---Checks if the byte at offset is a UTF-8 continuation byte.
|
||||
---
|
||||
---UTF-8 encodes code points in 1 to 4 bytes.
|
||||
---For a multi-byte sequence, each byte following the start byte is a continuation byte.
|
||||
---@param s string
|
||||
---@param offset? integer The offset of the string to start searching. Defaults to 1.
|
||||
---@return boolean
|
||||
function common.is_utf8_cont(s, offset)
|
||||
local byte = s:byte(offset or 1)
|
||||
return byte >= 0x80 and byte < 0xc0
|
||||
end
|
||||
|
||||
|
||||
---Returns an iterator that yields a UTF-8 character on each iteration.
|
||||
---@param text string
|
||||
---@return fun(): string
|
||||
function common.utf8_chars(text)
|
||||
return text:gmatch("[\0-\x7f\xc2-\xf4][\x80-\xbf]*")
|
||||
end
|
||||
|
||||
|
||||
---Clamps the number n between lo and hi.
|
||||
---@param n number
|
||||
---@param lo number
|
||||
---@param hi number
|
||||
---@return number
|
||||
function common.clamp(n, lo, hi)
|
||||
return math.max(math.min(n, hi), lo)
|
||||
end
|
||||
|
||||
|
||||
---Returns a new table containing the contents of b merged into a.
|
||||
---@param a table|nil
|
||||
---@param b table?
|
||||
---@return table
|
||||
function common.merge(a, b)
|
||||
a = type(a) == "table" and a or {}
|
||||
local t = {}
|
||||
|
@ -31,11 +51,19 @@ function common.merge(a, b)
|
|||
end
|
||||
|
||||
|
||||
---Returns the value of a number rounded to the nearest integer.
|
||||
---@param n number
|
||||
---@return number
|
||||
function common.round(n)
|
||||
return n >= 0 and math.floor(n + 0.5) or math.ceil(n - 0.5)
|
||||
end
|
||||
|
||||
|
||||
---Returns the first index where a subtable in tbl has prop set.
|
||||
---If none is found, nil is returned.
|
||||
---@param tbl table
|
||||
---@param prop any
|
||||
---@return number|nil
|
||||
function common.find_index(tbl, prop)
|
||||
for i, o in ipairs(tbl) do
|
||||
if o[prop] then return i end
|
||||
|
@ -43,6 +71,16 @@ function common.find_index(tbl, prop)
|
|||
end
|
||||
|
||||
|
||||
---Returns a value between a and b on a linear scale, based on the
|
||||
---interpolation point t.
|
||||
---
|
||||
---If a and b are tables, a table containing the result for all the
|
||||
---elements in a and b is returned.
|
||||
---@param a number
|
||||
---@param b number
|
||||
---@param t number
|
||||
---@return number
|
||||
---@overload fun(a: table, b: table, t: number): table
|
||||
function common.lerp(a, b, t)
|
||||
if type(a) ~= "table" then
|
||||
return a + (b - a) * t
|
||||
|
@ -55,11 +93,29 @@ function common.lerp(a, b, t)
|
|||
end
|
||||
|
||||
|
||||
---Returns the euclidean distance between two points.
|
||||
---@param x1 number
|
||||
---@param y1 number
|
||||
---@param x2 number
|
||||
---@param y2 number
|
||||
---@return number
|
||||
function common.distance(x1, y1, x2, y2)
|
||||
return math.sqrt(((x2-x1) ^ 2)+((y2-y1) ^ 2))
|
||||
end
|
||||
|
||||
|
||||
---Parses a CSS color string.
|
||||
---
|
||||
---Only these formats are supported:
|
||||
---* `rgb(r, g, b)`
|
||||
---* `rgba(r, g, b, a)`
|
||||
---* `#rrggbbaa`
|
||||
---* `#rrggbb`
|
||||
---@param str string
|
||||
---@return number r
|
||||
---@return number g
|
||||
---@return number b
|
||||
---@return number a
|
||||
function common.color(str)
|
||||
local r, g, b, a = str:match("^#(%x%x)(%x%x)(%x%x)(%x?%x?)$")
|
||||
if r then
|
||||
|
@ -80,24 +136,19 @@ function common.color(str)
|
|||
end
|
||||
|
||||
|
||||
---Splices a numerically indexed table.
|
||||
---This function mutates the original table.
|
||||
---@param t any[]
|
||||
---@param at number Index at which to start splicing.
|
||||
---@param remove number Number of elements to remove.
|
||||
---@param insert? any[] A table containing elements to insert after splicing.
|
||||
function common.splice(t, at, remove, insert)
|
||||
assert(remove >= 0, "bad argument #3 to 'splice' (non-negative value expected)")
|
||||
insert = insert or {}
|
||||
local offset = #insert - remove
|
||||
local old_len = #t
|
||||
if offset < 0 then
|
||||
for i = at - offset, old_len - offset do
|
||||
t[i + offset] = t[i]
|
||||
local len = #insert
|
||||
if remove ~= len then table.move(t, at + remove, #t + remove, at + len) end
|
||||
table.move(insert, 1, len, at, t)
|
||||
end
|
||||
elseif offset > 0 then
|
||||
for i = old_len, at, -1 do
|
||||
t[i + offset] = t[i]
|
||||
end
|
||||
end
|
||||
for i, item in ipairs(insert) do
|
||||
t[at + i - 1] = item
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function compare_score(a, b)
|
||||
|
@ -120,6 +171,16 @@ local function fuzzy_match_items(items, needle, files)
|
|||
end
|
||||
|
||||
|
||||
---Performs fuzzy matching.
|
||||
---
|
||||
---If the haystack is a string, a score ranging from 0 to 1 is returned. </br>
|
||||
---If the haystack is a table, a table containing the haystack sorted in ascending
|
||||
---order of similarity is returned.
|
||||
---@param haystack string
|
||||
---@param needle string
|
||||
---@param files boolean If true, the matching process will be performed in reverse to better match paths.
|
||||
---@return number
|
||||
---@overload fun(haystack: string[], needle: string, files: boolean): string[]
|
||||
function common.fuzzy_match(haystack, needle, files)
|
||||
if type(haystack) == "table" then
|
||||
return fuzzy_match_items(haystack, needle, files)
|
||||
|
@ -128,6 +189,14 @@ function common.fuzzy_match(haystack, needle, files)
|
|||
end
|
||||
|
||||
|
||||
---Performs fuzzy matching and returns recently used strings if needed.
|
||||
---
|
||||
---If the needle is empty, then a list of recently used strings
|
||||
---are added to the result, followed by strings from the haystack.
|
||||
---@param haystack string[]
|
||||
---@param recents string[]
|
||||
---@param needle string
|
||||
---@return string[]
|
||||
function common.fuzzy_match_with_recents(haystack, recents, needle)
|
||||
if needle == "" then
|
||||
local recents_ext = {}
|
||||
|
@ -146,11 +215,24 @@ function common.fuzzy_match_with_recents(haystack, recents, needle)
|
|||
end
|
||||
|
||||
|
||||
---Returns a list of paths that are relative to the input path.
|
||||
---
|
||||
---If a root directory is specified, the function returns paths
|
||||
---that are relative to the root directory.
|
||||
---@param text string The input path.
|
||||
---@param root? string The root directory.
|
||||
---@return string[]
|
||||
function common.path_suggest(text, root)
|
||||
if root and root:sub(-1) ~= PATHSEP then
|
||||
root = root .. PATHSEP
|
||||
end
|
||||
local path, name = text:match("^(.-)([^:/\\]*)$")
|
||||
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)
|
||||
|
@ -199,8 +281,16 @@ function common.path_suggest(text, root)
|
|||
end
|
||||
|
||||
|
||||
---Returns a list of directories that are related to a path.
|
||||
---@param text string The input path.
|
||||
---@return string[]
|
||||
function common.dir_path_suggest(text)
|
||||
local path, name = text:match("^(.-)([^:/\\]*)$")
|
||||
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
|
||||
|
@ -214,8 +304,18 @@ function common.dir_path_suggest(text)
|
|||
end
|
||||
|
||||
|
||||
---Filters a list of paths to find those that are related to the input path.
|
||||
---@param text string The input path.
|
||||
---@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("^(.-)([^:/\\]*)$")
|
||||
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
|
||||
|
@ -226,6 +326,15 @@ function common.dir_list_suggest(text, dir_list)
|
|||
end
|
||||
|
||||
|
||||
---Matches a string against a list of patterns.
|
||||
---
|
||||
---If a match was found, its start and end index is returned.
|
||||
---Otherwise, false is returned.
|
||||
---@param text string
|
||||
---@param pattern string|string[]
|
||||
---@param ... any Other options for string.find().
|
||||
---@return number|boolean start_index
|
||||
---@return number|nil end_index
|
||||
function common.match_pattern(text, pattern, ...)
|
||||
if type(pattern) == "string" then
|
||||
return text:find(pattern, ...)
|
||||
|
@ -238,8 +347,24 @@ function common.match_pattern(text, pattern, ...)
|
|||
end
|
||||
|
||||
|
||||
---Draws text onto the window.
|
||||
---The function returns the X and Y coordinates of the bottom-right
|
||||
---corner of the text.
|
||||
---@param font renderer.font
|
||||
---@param color renderer.color
|
||||
---@param text string
|
||||
---@param align string
|
||||
---| '"left"' # Align text to the left of the bounding box
|
||||
---| '"right"' # Align text to the right of the bounding box
|
||||
---| '"center"' # Center text in the bounding box
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@param w number
|
||||
---@param h number
|
||||
---@return number x_advance
|
||||
---@return number y_advance
|
||||
function common.draw_text(font, color, text, align, x,y,w,h)
|
||||
local tw, th = font:get_width(text), font:get_height(text)
|
||||
local tw, th = font:get_width(text), font:get_height()
|
||||
if align == "center" then
|
||||
x = x + (w - tw) / 2
|
||||
elseif align == "right" then
|
||||
|
@ -250,6 +375,16 @@ function common.draw_text(font, color, text, align, x,y,w,h)
|
|||
end
|
||||
|
||||
|
||||
---Prints the execution time of a function.
|
||||
---
|
||||
---The execution time and percentage of frame time
|
||||
---for the function is printed to standard output. </br>
|
||||
---The frame rate is always assumed to be 60 FPS, thus
|
||||
---a value of 100% would mean that the benchmark took
|
||||
---1/60 of a second to execute.
|
||||
---@param name string
|
||||
---@param fn fun(...: any): any
|
||||
---@return any # The result returned by the function
|
||||
function common.bench(name, fn, ...)
|
||||
local start = system.get_time()
|
||||
local res = fn(...)
|
||||
|
@ -260,12 +395,15 @@ function common.bench(name, fn, ...)
|
|||
return res
|
||||
end
|
||||
|
||||
-- From gvx/Ser
|
||||
local oddvals = {[tostring(1/0)] = "1/0", [tostring(-1/0)] = "-1/0", [tostring(-(0/0))] = "-(0/0)", [tostring(0/0)] = "0/0"}
|
||||
|
||||
local function serialize(val, pretty, indent_str, escape, sort, limit, level)
|
||||
local space = pretty and " " or ""
|
||||
local indent = pretty and string.rep(indent_str, level) or ""
|
||||
local newline = pretty and "\n" or ""
|
||||
if type(val) == "string" then
|
||||
local ty = type(val)
|
||||
if ty == "string" then
|
||||
local out = string.format("%q", val)
|
||||
if escape then
|
||||
out = string.gsub(out, "\\\n", "\\n")
|
||||
|
@ -277,7 +415,7 @@ local function serialize(val, pretty, indent_str, escape, sort, limit, level)
|
|||
out = string.gsub(out, "\\13", "\\r")
|
||||
end
|
||||
return out
|
||||
elseif type(val) == "table" then
|
||||
elseif ty == "table" then
|
||||
-- early exit
|
||||
if level >= limit then return tostring(val) end
|
||||
local next_indent = pretty and (indent .. indent_str) or ""
|
||||
|
@ -292,17 +430,37 @@ local function serialize(val, pretty, indent_str, escape, sort, limit, level)
|
|||
if sort then table.sort(t) end
|
||||
return "{" .. newline .. table.concat(t, "," .. newline) .. newline .. indent .. "}"
|
||||
end
|
||||
if ty == "number" then
|
||||
-- tostring is locale-dependent, so we need to replace an eventual `,` with `.`
|
||||
local res, _ = tostring(val):gsub(",", ".")
|
||||
-- handle inf/nan
|
||||
return oddvals[res] or res
|
||||
end
|
||||
return tostring(val)
|
||||
end
|
||||
|
||||
-- Serialize `val` into a parsable string.
|
||||
-- Available options
|
||||
-- * pretty: enable pretty printing
|
||||
-- * indent_str: indent to use (" " by default)
|
||||
-- * escape: use normal escape characters instead of the ones used by string.format("%q", ...)
|
||||
-- * sort: sort the keys inside tables
|
||||
-- * limit: limit how deep to serialize
|
||||
-- * initial_indent: the initial indentation level
|
||||
|
||||
---@class common.serializeoptions
|
||||
---@field pretty boolean Enables pretty printing.
|
||||
---@field indent_str string The indentation character to use. Defaults to `" "`.
|
||||
---@field escape boolean Uses normal escape characters ("\n") instead of decimal escape sequences ("\10").
|
||||
---@field limit number Limits the depth when serializing nested tables. Defaults to `math.huge`.
|
||||
---@field sort boolean Sorts the output if it is a sortable table.
|
||||
---@field initial_indent number The initial indentation level. Defaults to 0.
|
||||
|
||||
---Serializes a value into a Lua string that is loadable with load().
|
||||
---
|
||||
---Only these basic types are supported:
|
||||
---* nil
|
||||
---* boolean
|
||||
---* number (except very large numbers and special constants, e.g. `math.huge`, `inf` and `nan`)
|
||||
---* integer
|
||||
---* string
|
||||
---* table
|
||||
---
|
||||
---@param val any
|
||||
---@param opts? common.serializeoptions
|
||||
---@return string
|
||||
function common.serialize(val, opts)
|
||||
opts = opts or {}
|
||||
local indent_str = opts.indent_str or " "
|
||||
|
@ -314,19 +472,52 @@ function common.serialize(val, opts)
|
|||
end
|
||||
|
||||
|
||||
---Returns the last portion of a path.
|
||||
---@param path string
|
||||
---@return string
|
||||
function common.basename(path)
|
||||
-- a path should never end by / or \ except if it is '/' (unix root) or
|
||||
-- 'X:\' (windows drive)
|
||||
return path:match("[^\\/]+$") or path
|
||||
return path:match("[^"..PATHSEP.."]+$") or path
|
||||
end
|
||||
|
||||
|
||||
-- can return nil if there is no directory part in the path
|
||||
---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)
|
||||
return path:match("(.+)[:\\/][^\\/]+$")
|
||||
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
|
||||
|
||||
|
||||
---Returns a path where the user's home directory is replaced by `"~"`.
|
||||
---@param text string
|
||||
---@return string
|
||||
function common.home_encode(text)
|
||||
if HOME and string.find(text, HOME, 1, true) == 1 then
|
||||
local dir_pos = #HOME + 1
|
||||
|
@ -340,6 +531,9 @@ function common.home_encode(text)
|
|||
end
|
||||
|
||||
|
||||
---Returns a list of paths where the user's home directory is replaced by `"~"`.
|
||||
---@param paths string[] A list of paths to encode
|
||||
---@return string[]
|
||||
function common.home_encode_list(paths)
|
||||
local t = {}
|
||||
for i = 1, #paths do
|
||||
|
@ -349,6 +543,10 @@ function common.home_encode_list(paths)
|
|||
end
|
||||
|
||||
|
||||
---Expands the `"~"` prefix in a path into the user's home directory.
|
||||
---This function is not guaranteed to return an absolute path.
|
||||
---@param text string
|
||||
---@return string
|
||||
function common.home_expand(text)
|
||||
if text == nil then
|
||||
return HOME
|
||||
|
@ -359,22 +557,30 @@ end
|
|||
|
||||
local function split_on_slash(s, sep_pattern)
|
||||
local t = {}
|
||||
if s:match("^[/\\]") then
|
||||
if s:match("^["..PATHSEP.."]") then
|
||||
t[#t + 1] = ""
|
||||
end
|
||||
for fragment in string.gmatch(s, "([^/\\]+)") do
|
||||
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
|
||||
return t
|
||||
end
|
||||
|
||||
|
||||
-- The filename argument given to the function is supposed to
|
||||
-- come from system.absolute_path and as such should be an
|
||||
-- absolute path without . or .. elements.
|
||||
-- This function exists because on Windows the drive letter returned
|
||||
-- by system.absolute_path is sometimes with a lower case and sometimes
|
||||
-- with an upper case so we normalize to upper case.
|
||||
---Normalizes the drive letter in a Windows path to uppercase.
|
||||
---This function expects an absolute path, e.g. a path from `system.absolute_path`.
|
||||
---
|
||||
---This function is needed because the path returned by `system.absolute_path`
|
||||
---may contain drive letters in upper or lowercase.
|
||||
---@param filename string|nil The input path.
|
||||
---@return string|nil
|
||||
function common.normalize_volume(filename)
|
||||
if not filename then return end
|
||||
if PATHSEP == '\\' then
|
||||
|
@ -383,10 +589,23 @@ 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
|
||||
|
||||
|
||||
---Normalizes a path into the same format across platforms.
|
||||
---
|
||||
---On Windows, all drive letters are converted to uppercase.
|
||||
---UNC paths with drive letters are converted back to ordinary Windows paths.
|
||||
---All path separators (`"/"`, `"\\"`) are converted to platform-specific ones.
|
||||
---@param filename string|nil
|
||||
---@return string|nil
|
||||
function common.normalize_path(filename)
|
||||
if not filename then return end
|
||||
local volume
|
||||
|
@ -401,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
|
||||
|
@ -427,18 +651,32 @@ function common.normalize_path(filename)
|
|||
end
|
||||
|
||||
|
||||
---Checks whether a path is absolute or relative.
|
||||
---@param path string
|
||||
---@return boolean
|
||||
function common.is_absolute_path(path)
|
||||
return path:sub(1, 1) == PATHSEP or path:match("^(%a):\\") or path:match('^(%w*):')
|
||||
return path:sub(1, 1) == PATHSEP or path:match("^(%a):\\") or path:match('^([%w%s]*):')
|
||||
end
|
||||
|
||||
|
||||
---Checks whether a path belongs to a parent directory.
|
||||
---@param filename string The path to check.
|
||||
---@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
|
||||
|
||||
|
||||
---Checks whether a path is relative to another path.
|
||||
---@param ref_dir string The path to check against.
|
||||
---@param dir string The input path.
|
||||
---@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:\
|
||||
|
@ -462,6 +700,11 @@ function common.relative_path(ref_dir, dir)
|
|||
end
|
||||
|
||||
|
||||
---Creates a directory recursively if necessary.
|
||||
---@param path string
|
||||
---@return boolean success
|
||||
---@return string|nil error
|
||||
---@return string|nil path The path where an error occured.
|
||||
function common.mkdirp(path)
|
||||
local stat = system.get_file_info(path)
|
||||
if stat and stat.type then
|
||||
|
@ -471,12 +714,12 @@ function common.mkdirp(path)
|
|||
while path and path ~= "" do
|
||||
local success_mkdir = system.mkdir(path)
|
||||
if success_mkdir then break end
|
||||
local updir, basedir = path:match("(.*)[/\\](.+)$")
|
||||
local updir, basedir = path:match("(.*)["..PATHSEP.."](.+)$")
|
||||
table.insert(subdirs, 1, basedir or 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
|
||||
|
@ -484,6 +727,13 @@ function common.mkdirp(path)
|
|||
return true
|
||||
end
|
||||
|
||||
|
||||
---Removes a path.
|
||||
---@param path string
|
||||
---@param recursively boolean If true, the function will attempt to remove everything in the specified path.
|
||||
---@return boolean success
|
||||
---@return string|nil error
|
||||
---@return string|nil path The path where the error occured.
|
||||
function common.rm(path, recursively)
|
||||
local stat = system.get_file_info(path)
|
||||
if not stat or (stat.type ~= "file" and stat.type ~= "dir") then
|
||||
|
@ -533,4 +783,3 @@ end
|
|||
|
||||
|
||||
return common
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
local common = require "core.common"
|
||||
|
||||
local config = {}
|
||||
|
||||
config.fps = 60
|
||||
|
@ -55,18 +57,49 @@ config.max_clicks = 3
|
|||
-- 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 = {}
|
||||
|
||||
-- virtual representation of plugins config table
|
||||
config.plugins = {}
|
||||
-- Allow you to set plugin configs even if we haven't seen the plugin before.
|
||||
|
||||
-- allows virtual access to the plugins config table
|
||||
setmetatable(config.plugins, {
|
||||
__index = function(t, k)
|
||||
local v = rawget(t, k)
|
||||
if v == true or v == nil then v = {} rawset(t, k, v) end
|
||||
return v
|
||||
__index = function(_, k)
|
||||
if not plugins_config[k] then
|
||||
plugins_config[k] = { enabled = true, config = {} }
|
||||
end
|
||||
if plugins_config[k].enabled ~= false then
|
||||
return plugins_config[k].config
|
||||
end
|
||||
return false
|
||||
end,
|
||||
__newindex = function(_, k, v)
|
||||
if not plugins_config[k] then
|
||||
plugins_config[k] = { enabled = nil, config = {} }
|
||||
end
|
||||
if v == false and package.loaded["plugins."..k] then
|
||||
local core = require "core"
|
||||
core.warn("[%s] is already enabled, restart the editor for the change to take effect", k)
|
||||
return
|
||||
elseif plugins_config[k].enabled == false and v ~= false then
|
||||
plugins_config[k].enabled = true
|
||||
end
|
||||
if v == false then
|
||||
plugins_config[k].enabled = false
|
||||
elseif type(v) == "table" then
|
||||
plugins_config[k].enabled = true
|
||||
plugins_config[k].config = common.merge(plugins_config[k].config, v)
|
||||
end
|
||||
end,
|
||||
__pairs = function()
|
||||
return coroutine.wrap(function()
|
||||
for name, status in pairs(plugins_config) do
|
||||
coroutine.yield(name, status.config)
|
||||
end
|
||||
end)
|
||||
end
|
||||
})
|
||||
|
||||
-- Disable these plugins by default.
|
||||
config.plugins.trimwhitespace = false
|
||||
config.plugins.drawwhitespace = false
|
||||
|
||||
return config
|
||||
|
|
|
@ -12,11 +12,31 @@ local divider_width = 1
|
|||
local divider_padding = 5
|
||||
local DIVIDER = {}
|
||||
|
||||
---An item in the context menu.
|
||||
---@class core.contextmenu.item
|
||||
---@field text string
|
||||
---@field info string|nil If provided, this text is displayed on the right side of the menu.
|
||||
---@field command string|fun()
|
||||
|
||||
---A list of items with the same predicate.
|
||||
---@see core.command.predicate
|
||||
---@class core.contextmenu.itemset
|
||||
---@field predicate core.command.predicate
|
||||
---@field items core.contextmenu.item[]
|
||||
|
||||
---A context menu.
|
||||
---@class core.contextmenu : core.object
|
||||
---@field itemset core.contextmenu.itemset[]
|
||||
---@field show_context_menu boolean
|
||||
---@field selected number
|
||||
---@field position core.view.position
|
||||
---@field current_scale number
|
||||
local ContextMenu = Object:extend()
|
||||
|
||||
---A unique value representing the divider in a context menu.
|
||||
ContextMenu.DIVIDER = DIVIDER
|
||||
|
||||
---Creates a new context menu.
|
||||
function ContextMenu:new()
|
||||
self.itemset = {}
|
||||
self.show_context_menu = false
|
||||
|
@ -55,12 +75,19 @@ local function update_items_size(items, update_binding)
|
|||
items.width, items.height = width, height
|
||||
end
|
||||
|
||||
---Registers a list of items into the context menu with a predicate.
|
||||
---@param predicate core.command.predicate
|
||||
---@param items core.contextmenu.item[]
|
||||
function ContextMenu:register(predicate, items)
|
||||
predicate = command.generate_predicate(predicate)
|
||||
update_items_size(items, true)
|
||||
table.insert(self.itemset, { predicate = predicate, items = items })
|
||||
end
|
||||
|
||||
---Shows the context menu.
|
||||
---@param x number
|
||||
---@param y number
|
||||
---@return boolean # If true, the context menu is shown.
|
||||
function ContextMenu:show(x, y)
|
||||
self.items = nil
|
||||
local items_list = { width = 0, height = 0 }
|
||||
|
@ -94,6 +121,7 @@ function ContextMenu:show(x, y)
|
|||
return false
|
||||
end
|
||||
|
||||
---Hides the context menu.
|
||||
function ContextMenu:hide()
|
||||
self.show_context_menu = false
|
||||
self.items = nil
|
||||
|
@ -102,6 +130,8 @@ function ContextMenu:hide()
|
|||
core.request_cursor(core.active_view.cursor)
|
||||
end
|
||||
|
||||
---Returns an iterator that iterates over each context menu item and their dimensions.
|
||||
---@return fun(): number, core.contextmenu.item, number, number, number, number
|
||||
function ContextMenu:each_item()
|
||||
local x, y, w = self.position.x, self.position.y, self.items.width
|
||||
local oy = y
|
||||
|
@ -115,8 +145,12 @@ function ContextMenu:each_item()
|
|||
end)
|
||||
end
|
||||
|
||||
---Event handler for mouse movements.
|
||||
---@param px any
|
||||
---@param py any
|
||||
---@return boolean # true if the event is caught.
|
||||
function ContextMenu:on_mouse_moved(px, py)
|
||||
if not self.show_context_menu then return end
|
||||
if not self.show_context_menu then return false end
|
||||
|
||||
self.selected = -1
|
||||
for i, item, x, y, w, h in self:each_item() do
|
||||
|
@ -128,6 +162,8 @@ function ContextMenu:on_mouse_moved(px, py)
|
|||
return true
|
||||
end
|
||||
|
||||
---Event handler for when the selection is confirmed.
|
||||
---@param item core.contextmenu.item
|
||||
function ContextMenu:on_selected(item)
|
||||
if type(item.command) == "string" then
|
||||
command.perform(item.command)
|
||||
|
@ -140,6 +176,7 @@ local function change_value(value, change)
|
|||
return value + change
|
||||
end
|
||||
|
||||
---Selects the the previous item.
|
||||
function ContextMenu:focus_previous()
|
||||
self.selected = (self.selected == -1 or self.selected == 1) and #self.items or change_value(self.selected, -1)
|
||||
if self:get_item_selected() == DIVIDER then
|
||||
|
@ -147,6 +184,7 @@ function ContextMenu:focus_previous()
|
|||
end
|
||||
end
|
||||
|
||||
---Selects the next item.
|
||||
function ContextMenu:focus_next()
|
||||
self.selected = (self.selected == -1 or self.selected == #self.items) and 1 or change_value(self.selected, 1)
|
||||
if self:get_item_selected() == DIVIDER then
|
||||
|
@ -154,10 +192,13 @@ function ContextMenu:focus_next()
|
|||
end
|
||||
end
|
||||
|
||||
---Gets the currently selected item.
|
||||
---@return core.contextmenu.item|nil
|
||||
function ContextMenu:get_item_selected()
|
||||
return (self.items or {})[self.selected]
|
||||
end
|
||||
|
||||
---Hides the context menu and performs the command if an item is selected.
|
||||
function ContextMenu:call_selected_item()
|
||||
local selected = self:get_item_selected()
|
||||
self:hide()
|
||||
|
@ -166,6 +207,12 @@ function ContextMenu:call_selected_item()
|
|||
end
|
||||
end
|
||||
|
||||
---Event handler for mouse press.
|
||||
---@param button core.view.mousebutton
|
||||
---@param px number
|
||||
---@param py number
|
||||
---@param clicks number
|
||||
---@return boolean # true if the event is caught.
|
||||
function ContextMenu:on_mouse_pressed(button, px, py, clicks)
|
||||
local caught = false
|
||||
|
||||
|
@ -186,14 +233,20 @@ function ContextMenu:on_mouse_pressed(button, px, py, clicks)
|
|||
return caught
|
||||
end
|
||||
|
||||
---@type fun(self: table, k: string, dest: number, rate?: number, name?: string)
|
||||
ContextMenu.move_towards = View.move_towards
|
||||
|
||||
---Event handler for content update.
|
||||
function ContextMenu:update()
|
||||
if self.show_context_menu then
|
||||
self:move_towards("height", self.items.height, nil, "contextmenu")
|
||||
end
|
||||
end
|
||||
|
||||
---Draws the context menu.
|
||||
---
|
||||
---This wraps `ContextMenu:draw_context_menu()`.
|
||||
---@see core.contextmenu.draw_context_menu
|
||||
function ContextMenu:draw()
|
||||
if not self.show_context_menu then return end
|
||||
if self.current_scale ~= SCALE then
|
||||
|
@ -206,6 +259,7 @@ function ContextMenu:draw()
|
|||
core.root_view:defer_draw(self.draw_context_menu, self)
|
||||
end
|
||||
|
||||
---Draws the context menu.
|
||||
function ContextMenu:draw_context_menu()
|
||||
if not self.items then return end
|
||||
local bx, by, bw, bh = self.position.x, self.position.y, self.items.width, self.height
|
||||
|
|
|
@ -91,6 +91,7 @@ end
|
|||
-- designed to be run inside a coroutine.
|
||||
function dirwatch:check(change_callback, scan_time, wait_time)
|
||||
local had_change = false
|
||||
local last_error
|
||||
self.monitor:check(function(id)
|
||||
had_change = true
|
||||
if self.monitor:mode() == "single" then
|
||||
|
@ -102,7 +103,10 @@ function dirwatch:check(change_callback, scan_time, wait_time)
|
|||
elseif self.reverse_watched[id] then
|
||||
change_callback(self.reverse_watched[id])
|
||||
end
|
||||
end, function(err)
|
||||
last_error = err
|
||||
end)
|
||||
if last_error ~= nil then error(last_error) end
|
||||
local start_time = system.get_time()
|
||||
for directory, old_modified in pairs(self.scanned) do
|
||||
if old_modified then
|
||||
|
@ -173,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
|
||||
|
@ -186,47 +191,46 @@ end
|
|||
-- "root" will by an absolute path without trailing '/'
|
||||
-- "path" will be a path starting without '/' and without trailing '/'
|
||||
-- or the empty string.
|
||||
-- It will identifies a sub-path within "root.
|
||||
-- It identifies a sub-path within "root".
|
||||
-- The current path location will therefore always be: root .. path.
|
||||
-- When recursing "root" will always be the same, only "path" will change.
|
||||
-- When recursing, "root" will always be the same, only "path" will change.
|
||||
-- Returns a list of file "items". In each item the "filename" will be the
|
||||
-- complete file path relative to "root" *without* the trailing '/', and without the starting '/'.
|
||||
function dirwatch.get_directory_files(dir, root, path, t, entries_count, recurse_pred)
|
||||
function dirwatch.get_directory_files(dir, root, path, entries_count, recurse_pred)
|
||||
local t = {}
|
||||
local t0 = system.get_time()
|
||||
local t_elapsed = system.get_time() - t0
|
||||
local dirs, files = {}, {}
|
||||
local ignore_compiled = compile_ignore_files()
|
||||
|
||||
local all = system.list_dir(common.basepath(root) .. path)
|
||||
|
||||
local all = system.list_dir(root .. PATHSEP .. path)
|
||||
if not all then return nil end
|
||||
|
||||
for _, file in ipairs(all or {}) do
|
||||
local entries = { }
|
||||
for _, file in ipairs(all) do
|
||||
local info = get_project_file_info(root, (path ~= "" and (path .. PATHSEP) or "") .. file, ignore_compiled)
|
||||
if info then
|
||||
table.insert(info.type == "dir" and dirs or files, info)
|
||||
entries_count = entries_count + 1
|
||||
table.insert(entries, info)
|
||||
end
|
||||
end
|
||||
table.sort(entries, compare_file)
|
||||
|
||||
local recurse_complete = true
|
||||
table.sort(dirs, compare_file)
|
||||
for _, f in ipairs(dirs) do
|
||||
table.insert(t, f)
|
||||
if recurse_pred(dir, f.filename, entries_count, t_elapsed) then
|
||||
local _, complete, n = dirwatch.get_directory_files(dir, root, f.filename, t, entries_count, recurse_pred)
|
||||
for _, info in ipairs(entries) do
|
||||
table.insert(t, info)
|
||||
entries_count = entries_count + 1
|
||||
if info.type == "dir" then
|
||||
if recurse_pred(dir, info.filename, entries_count, system.get_time() - t0) then
|
||||
local t_rec, complete, n = dirwatch.get_directory_files(dir, root, info.filename, entries_count, recurse_pred)
|
||||
recurse_complete = recurse_complete and complete
|
||||
if n ~= nil then
|
||||
entries_count = n
|
||||
for _, info_rec in ipairs(t_rec) do
|
||||
table.insert(t, info_rec)
|
||||
end
|
||||
end
|
||||
else
|
||||
recurse_complete = false
|
||||
end
|
||||
end
|
||||
|
||||
table.sort(files, compare_file)
|
||||
for _, f in ipairs(files) do
|
||||
table.insert(t, f)
|
||||
end
|
||||
|
||||
return t, recurse_complete, entries_count
|
||||
|
|
|
@ -19,25 +19,34 @@ function Highlighter:start()
|
|||
if self.running then return end
|
||||
self.running = true
|
||||
core.add_thread(function()
|
||||
while self.first_invalid_line < self.max_wanted_line do
|
||||
while self.first_invalid_line <= self.max_wanted_line do
|
||||
local max = math.min(self.first_invalid_line + 40, self.max_wanted_line)
|
||||
local retokenized_from
|
||||
for i = self.first_invalid_line, max do
|
||||
local state = (i > 1) and self.lines[i - 1].state
|
||||
local line = self.lines[i]
|
||||
if not (line and line.init_state == state and line.text == self.doc.lines[i]) then
|
||||
if line and line.resume and (line.init_state ~= state or line.text ~= self.doc.lines[i]) then
|
||||
-- Reset the progress if no longer valid
|
||||
line.resume = nil
|
||||
end
|
||||
if not (line and line.init_state == state and line.text == self.doc.lines[i] and not line.resume) then
|
||||
retokenized_from = retokenized_from or i
|
||||
self.lines[i] = self:tokenize_line(i, state)
|
||||
self.lines[i] = self:tokenize_line(i, state, line and line.resume)
|
||||
if self.lines[i].resume then
|
||||
self.first_invalid_line = i
|
||||
goto yield
|
||||
end
|
||||
elseif retokenized_from then
|
||||
self:update_notify(retokenized_from, i - retokenized_from - 1)
|
||||
retokenized_from = nil
|
||||
end
|
||||
end
|
||||
|
||||
self.first_invalid_line = max + 1
|
||||
::yield::
|
||||
if retokenized_from then
|
||||
self:update_notify(retokenized_from, max - retokenized_from)
|
||||
end
|
||||
|
||||
self.first_invalid_line = max + 1
|
||||
core.redraw = true
|
||||
coroutine.yield()
|
||||
end
|
||||
|
@ -48,7 +57,7 @@ end
|
|||
|
||||
local function set_max_wanted_lines(self, amount)
|
||||
self.max_wanted_line = amount
|
||||
if self.first_invalid_line < self.max_wanted_line then
|
||||
if self.first_invalid_line <= self.max_wanted_line then
|
||||
self:start()
|
||||
end
|
||||
end
|
||||
|
@ -91,11 +100,11 @@ function Highlighter:update_notify(line, n)
|
|||
end
|
||||
|
||||
|
||||
function Highlighter:tokenize_line(idx, state)
|
||||
function Highlighter:tokenize_line(idx, state, resume)
|
||||
local res = {}
|
||||
res.init_state = state
|
||||
res.text = self.doc.lines[idx]
|
||||
res.tokens, res.state = tokenizer.tokenize(self.doc.syntax, res.text, state)
|
||||
res.tokens, res.state, res.resume = tokenizer.tokenize(self.doc.syntax, res.text, state, resume)
|
||||
return res
|
||||
end
|
||||
|
||||
|
|
|
@ -44,7 +44,12 @@ end
|
|||
|
||||
function Doc:reset_syntax()
|
||||
local header = self:get_text(1, 1, self:position_offset(1, 1, 128))
|
||||
local syn = syntax.get(self.filename or "", header)
|
||||
local path = self.abs_filename
|
||||
if not path and self.filename then
|
||||
path = common.basepath(core.project_dir) .. self.filename
|
||||
end
|
||||
if path then path = common.normalize_path(path) end
|
||||
local syn = syntax.get(path, header)
|
||||
if self.syntax ~= syn then
|
||||
self.syntax = syn
|
||||
self.highlighter:soft_reset()
|
||||
|
@ -118,6 +123,7 @@ end
|
|||
|
||||
function Doc:is_dirty()
|
||||
if self.new_file then
|
||||
if self.filename then return true end
|
||||
return #self.lines > 1 or #self.lines[1] > 1
|
||||
else
|
||||
return self.clean_change_id ~= self:get_change_id()
|
||||
|
@ -276,9 +282,13 @@ end
|
|||
-- End of cursor seciton.
|
||||
|
||||
function Doc:sanitize_position(line, col)
|
||||
line = common.clamp(line, 1, #self.lines)
|
||||
col = common.clamp(col, 1, #self.lines[line])
|
||||
return line, col
|
||||
local nlines = #self.lines
|
||||
if line > nlines then
|
||||
return nlines, #self.lines[nlines]
|
||||
elseif line < 1 then
|
||||
return 1, 1
|
||||
end
|
||||
return line, common.clamp(col, 1, #self.lines[line])
|
||||
end
|
||||
|
||||
|
||||
|
@ -427,25 +437,61 @@ function Doc:raw_remove(line1, col1, line2, col2, undo_stack, time)
|
|||
local before = self.lines[line1]:sub(1, col1 - 1)
|
||||
local after = self.lines[line2]:sub(col2)
|
||||
|
||||
-- splice line into line array
|
||||
common.splice(self.lines, line1, line2 - line1 + 1, { before .. after })
|
||||
|
||||
-- move all cursors back if they share a line with the removed text
|
||||
for idx, cline1, ccol1, cline2, ccol2 in self:get_selections(true, true) do
|
||||
if cline1 < line2 then break end
|
||||
local line_removal = line2 - line1
|
||||
local column_removal = line2 == cline2 and col2 < ccol1 and (line2 == line1 and col2 - col1 or col2) or 0
|
||||
self:set_selections(idx, cline1 - line_removal, ccol1 - column_removal, cline2 - line_removal, ccol2 - column_removal)
|
||||
local col_removal = col2 - col1
|
||||
|
||||
-- splice line into line array
|
||||
common.splice(self.lines, line1, line_removal + 1, { before .. after })
|
||||
|
||||
local merge = false
|
||||
|
||||
-- keep selections in correct positions: each pair (line, col)
|
||||
-- * remains unchanged if before the deleted text
|
||||
-- * is set to (line1, col1) if in the deleted text
|
||||
-- * is set to (line1, col - col_removal) if on line2 but out of the deleted text
|
||||
-- * is set to (line - line_removal, col) if after line2
|
||||
for idx, cline1, ccol1, cline2, ccol2 in self:get_selections(true, true) do
|
||||
if cline2 < line1 then break end
|
||||
local l1, c1, l2, c2 = cline1, ccol1, cline2, ccol2
|
||||
|
||||
if cline1 > line1 or (cline1 == line1 and ccol1 > col1) then
|
||||
if cline1 > line2 then
|
||||
l1 = l1 - line_removal
|
||||
else
|
||||
l1 = line1
|
||||
c1 = (cline1 == line2 and ccol1 > col2) and c1 - col_removal or col1
|
||||
end
|
||||
end
|
||||
|
||||
if cline2 > line1 or (cline2 == line1 and ccol2 > col1) then
|
||||
if cline2 > line2 then
|
||||
l2 = l2 - line_removal
|
||||
else
|
||||
l2 = line1
|
||||
c2 = (cline2 == line2 and ccol2 > col2) and c2 - col_removal or col1
|
||||
end
|
||||
end
|
||||
|
||||
if l1 == line1 and c1 == col1 then merge = true end
|
||||
self:set_selections(idx, l1, c1, l2, c2)
|
||||
end
|
||||
|
||||
if merge then
|
||||
self:merge_cursors()
|
||||
end
|
||||
|
||||
-- update highlighter and assure selection is in bounds
|
||||
self.highlighter:remove_notify(line1, line2 - line1)
|
||||
self.highlighter:remove_notify(line1, line_removal)
|
||||
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
|
||||
if self:get_change_id() < self.clean_change_id then
|
||||
self.clean_change_id = -1
|
||||
end
|
||||
line, col = self:sanitize_position(line, col)
|
||||
self:raw_insert(line, col, text, self.undo_stack, system.get_time())
|
||||
self:on_text_change("insert")
|
||||
|
|
|
@ -66,7 +66,18 @@ function search.find(doc, line, col, text, opt)
|
|||
s, e = search_func(line_text, pattern, col, plain)
|
||||
end
|
||||
if s then
|
||||
return line, s, line, e + 1
|
||||
local line2 = line
|
||||
-- If we've matched the newline too,
|
||||
-- return until the initial character of the next line.
|
||||
if e >= #doc.lines[line] then
|
||||
line2 = line + 1
|
||||
e = 0
|
||||
end
|
||||
-- Avoid returning matches that go beyond the last line.
|
||||
-- This is needed to avoid selecting the "last" newline.
|
||||
if line2 <= #doc.lines then
|
||||
return line, s, line2, e + 1
|
||||
end
|
||||
end
|
||||
col = opt.reverse and -1 or 1
|
||||
end
|
||||
|
|
|
@ -112,7 +112,8 @@ end
|
|||
|
||||
function DocView:get_scrollable_size()
|
||||
if not config.scroll_past_end then
|
||||
return self:get_line_height() * (#self.doc.lines) + style.padding.y * 2
|
||||
local _, _, _, h_scroll = self.h_scrollbar:get_track_rect()
|
||||
return self:get_line_height() * (#self.doc.lines) + style.padding.y * 2 + h_scroll
|
||||
end
|
||||
return self:get_line_height() * (#self.doc.lines - 1) + self.size.y
|
||||
end
|
||||
|
@ -160,26 +161,38 @@ end
|
|||
function DocView:get_visible_line_range()
|
||||
local x, y, x2, y2 = self:get_content_bounds()
|
||||
local lh = self:get_line_height()
|
||||
local minline = math.max(1, math.floor(y / lh))
|
||||
local maxline = math.min(#self.doc.lines, math.floor(y2 / lh) + 1)
|
||||
local minline = math.max(1, math.floor((y - style.padding.y) / lh) + 1)
|
||||
local maxline = math.min(#self.doc.lines, math.floor((y2 - style.padding.y) / lh) + 1)
|
||||
return minline, maxline
|
||||
end
|
||||
|
||||
|
||||
function DocView:get_col_x_offset(line, col)
|
||||
local default_font = self:get_font()
|
||||
local _, indent_size = self.doc:get_indent_info()
|
||||
default_font:set_tab_size(indent_size)
|
||||
local column = 1
|
||||
local xoffset = 0
|
||||
for _, type, text in self.doc.highlighter:each_token(line) do
|
||||
local font = style.syntax_fonts[type] or default_font
|
||||
if font ~= default_font then font:set_tab_size(indent_size) end
|
||||
local length = #text
|
||||
if column + length <= col then
|
||||
xoffset = xoffset + font:get_width(text)
|
||||
column = column + length
|
||||
if column >= col then
|
||||
return xoffset
|
||||
end
|
||||
else
|
||||
for char in common.utf8_chars(text) do
|
||||
if column == col then
|
||||
if column >= col then
|
||||
return xoffset
|
||||
end
|
||||
xoffset = xoffset + font:get_width(char)
|
||||
column = column + #char
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return xoffset
|
||||
end
|
||||
|
@ -190,8 +203,18 @@ function DocView:get_x_offset_col(line, x)
|
|||
|
||||
local xoffset, last_i, i = 0, 1, 1
|
||||
local default_font = self:get_font()
|
||||
local _, indent_size = self.doc:get_indent_info()
|
||||
default_font:set_tab_size(indent_size)
|
||||
for _, type, text in self.doc.highlighter:each_token(line) do
|
||||
local font = style.syntax_fonts[type] or default_font
|
||||
if font ~= default_font then font:set_tab_size(indent_size) end
|
||||
local width = font:get_width(text)
|
||||
-- Don't take the shortcut if the width matches x,
|
||||
-- because we need last_i which should be calculated using utf-8.
|
||||
if xoffset + width < x then
|
||||
xoffset = xoffset + width
|
||||
i = i + #text
|
||||
else
|
||||
for char in common.utf8_chars(text) do
|
||||
local w = font:get_width(char)
|
||||
if xoffset >= x then
|
||||
|
@ -202,6 +225,7 @@ function DocView:get_x_offset_col(line, x)
|
|||
i = i + #char
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return #line_text
|
||||
end
|
||||
|
@ -221,7 +245,8 @@ function DocView:scroll_to_line(line, ignore_if_visible, instant)
|
|||
if not (ignore_if_visible and line > min and line < max) then
|
||||
local x, y = self:get_line_screen_position(line)
|
||||
local ox, oy = self:get_content_offset()
|
||||
self.scroll.to.y = math.max(0, y - oy - self.size.y / 2)
|
||||
local _, _, _, scroll_h = self.h_scrollbar:get_track_rect()
|
||||
self.scroll.to.y = math.max(0, y - oy - (self.size.y - scroll_h) / 2)
|
||||
if instant then
|
||||
self.scroll.y = self.scroll.to.y
|
||||
end
|
||||
|
@ -230,17 +255,20 @@ end
|
|||
|
||||
|
||||
function DocView:scroll_to_make_visible(line, col)
|
||||
local ox, oy = self:get_content_offset()
|
||||
local _, oy = self:get_content_offset()
|
||||
local _, ly = self:get_line_screen_position(line, col)
|
||||
local lh = self:get_line_height()
|
||||
self.scroll.to.y = common.clamp(self.scroll.to.y, ly - oy - self.size.y + lh * 2, ly - oy - lh)
|
||||
local _, _, _, scroll_h = self.h_scrollbar:get_track_rect()
|
||||
self.scroll.to.y = common.clamp(self.scroll.to.y, ly - oy - self.size.y + scroll_h + lh * 2, ly - oy - lh)
|
||||
local gw = self:get_gutter_width()
|
||||
local xoffset = self:get_col_x_offset(line, col)
|
||||
local xmargin = 3 * self:get_font():get_width(' ')
|
||||
local xsup = xoffset + gw + xmargin
|
||||
local xinf = xoffset - xmargin
|
||||
if xsup > self.scroll.x + self.size.x then
|
||||
self.scroll.to.x = xsup - self.size.x
|
||||
local _, _, scroll_w = self.v_scrollbar:get_track_rect()
|
||||
local size_x = math.max(0, self.size.x - scroll_w)
|
||||
if xsup > self.scroll.x + size_x then
|
||||
self.scroll.to.x = xsup - size_x
|
||||
elseif xinf < self.scroll.x then
|
||||
self.scroll.to.x = math.max(0, xinf)
|
||||
end
|
||||
|
@ -413,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
|
||||
|
@ -422,6 +450,7 @@ function DocView:draw_line_text(line, x, y)
|
|||
-- do not render newline, fixes issue #1164
|
||||
if tidx == last_token then text = text:sub(1, -2) end
|
||||
tx = renderer.draw_text(font, text, tx, ty, color)
|
||||
if tx > self.position.x + self.size.x then break end
|
||||
end
|
||||
return self:get_line_height()
|
||||
end
|
||||
|
|
|
@ -18,13 +18,13 @@ local Doc
|
|||
local core = {}
|
||||
|
||||
local function load_session()
|
||||
local ok, t = pcall(dofile, USERDIR .. "/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 .. "/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())),
|
||||
|
@ -102,7 +102,7 @@ local function strip_leading_path(filename)
|
|||
end
|
||||
|
||||
local function strip_trailing_slash(filename)
|
||||
if filename:match("[^:][/\\]$") then
|
||||
if filename:match("[^:]["..PATHSEP.."]$") then
|
||||
return filename:sub(1, -2)
|
||||
end
|
||||
return filename
|
||||
|
@ -120,9 +120,7 @@ local function show_max_files_warning(dir)
|
|||
"Too many files in project directory: stopped reading at "..
|
||||
config.max_project_files.." files. For more information see "..
|
||||
"usage.md at https://github.com/lite-xl/lite-xl."
|
||||
if core.status_view then
|
||||
core.status_view:show_message("!", style.accent, message)
|
||||
end
|
||||
core.warn(message)
|
||||
end
|
||||
|
||||
|
||||
|
@ -184,13 +182,13 @@ local function refresh_directory(topdir, target)
|
|||
directory_start_idx = directory_start_idx + 1
|
||||
end
|
||||
|
||||
local files = dirwatch.get_directory_files(topdir, topdir.name, (target or ""), {}, 0, function() return false end)
|
||||
local files = dirwatch.get_directory_files(topdir, topdir.name, (target or ""), 0, function() return false end)
|
||||
local change = false
|
||||
|
||||
-- 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
|
||||
|
||||
|
@ -214,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
|
||||
|
@ -225,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
|
||||
|
@ -265,7 +263,7 @@ function core.add_project_directory(path)
|
|||
|
||||
local fstype = PLATFORM == "Linux" and system.get_fs_type(topdir.name) or "unknown"
|
||||
topdir.force_scans = (fstype == "nfs" or fstype == "fuse")
|
||||
local t, complete, entries_count = dirwatch.get_directory_files(topdir, topdir.name, "", {}, 0, timed_max_files_pred)
|
||||
local t, complete, entries_count = dirwatch.get_directory_files(topdir, topdir.name, "", 0, timed_max_files_pred)
|
||||
topdir.files = t
|
||||
if not complete then
|
||||
topdir.slow_filesystem = not complete and (entries_count <= config.max_project_files)
|
||||
|
@ -274,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)
|
||||
|
@ -288,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"})
|
||||
|
@ -305,7 +303,7 @@ function core.add_project_directory(path)
|
|||
end
|
||||
end
|
||||
if project_dir_open then
|
||||
coroutine.yield(changed and 0.05 or 0)
|
||||
coroutine.yield(changed and 0 or 0.05)
|
||||
else
|
||||
return
|
||||
end
|
||||
|
@ -375,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
|
||||
|
@ -389,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)
|
||||
|
@ -464,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
|
||||
|
@ -531,12 +529,9 @@ local style = require "core.style"
|
|||
|
||||
------------------------------ Plugins ----------------------------------------
|
||||
|
||||
-- enable or disable plugin loading setting config entries:
|
||||
-- disable plugin loading setting config entries:
|
||||
|
||||
-- enable plugins.trimwhitespace, otherwise it is disabled by default:
|
||||
-- config.plugins.trimwhitespace = true
|
||||
--
|
||||
-- disable detectindent, otherwise it is enabled by default
|
||||
-- disable plugin detectindent, otherwise it is enabled by default:
|
||||
-- config.plugins.detectindent = false
|
||||
|
||||
---------------------------- Miscellaneous -------------------------------------
|
||||
|
@ -577,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
|
||||
|
@ -607,7 +602,7 @@ function core.load_user_directory()
|
|||
if not stat_dir then
|
||||
create_user_directory()
|
||||
end
|
||||
local init_filename = USERDIR .. "/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)
|
||||
|
@ -640,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)
|
||||
|
@ -665,9 +660,9 @@ 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
|
||||
|
||||
|
@ -718,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
|
||||
|
@ -811,15 +806,19 @@ function core.init()
|
|||
end
|
||||
|
||||
if not plugins_success or got_user_error or got_project_error then
|
||||
-- defer LogView to after everything is initialized,
|
||||
-- so that EmptyView won't be added after LogView.
|
||||
core.add_thread(function()
|
||||
command.perform("core:open-log")
|
||||
end)
|
||||
end
|
||||
|
||||
core.configure_borderless_window()
|
||||
|
||||
if #plugins_refuse_list.userdir.plugins > 0 or #plugins_refuse_list.datadir.plugins > 0 then
|
||||
local opt = {
|
||||
{ font = style.font, text = "Exit", default_no = true },
|
||||
{ font = style.font, text = "Continue" , default_yes = true }
|
||||
{ text = "Exit", default_no = true },
|
||||
{ text = "Continue", default_yes = true }
|
||||
}
|
||||
local msg = {}
|
||||
for _, entry in pairs(plugins_refuse_list) do
|
||||
|
@ -860,8 +859,8 @@ function core.confirm_close_docs(docs, close_fn, ...)
|
|||
end
|
||||
local args = {...}
|
||||
local opt = {
|
||||
{ font = style.font, text = "Yes", default_yes = true },
|
||||
{ font = style.font, text = "No" , default_no = true }
|
||||
{ text = "Yes", default_yes = true },
|
||||
{ text = "No", default_no = true }
|
||||
}
|
||||
core.nag_view:show("Unsaved Changes", text, opt, function(item)
|
||||
if item.text == "Yes" then close_fn(table.unpack(args)) end
|
||||
|
@ -879,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
|
||||
|
@ -887,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
|
||||
|
||||
|
@ -924,7 +923,7 @@ end
|
|||
local function get_plugin_details(filename)
|
||||
local info = system.get_file_info(filename)
|
||||
if info ~= nil and info.type == "dir" then
|
||||
filename = filename .. "/init.lua"
|
||||
filename = filename .. PATHSEP .. "init.lua"
|
||||
info = system.get_file_info(filename)
|
||||
end
|
||||
if not info or not filename:match("%.lua$") then return false end
|
||||
|
@ -963,7 +962,7 @@ function core.load_plugins()
|
|||
}
|
||||
local files, ordered = {}, {}
|
||||
for _, root_dir in ipairs {DATADIR, USERDIR} do
|
||||
local plugin_dir = root_dir .. "/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(
|
||||
|
@ -978,7 +977,7 @@ 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 .. '/' .. plugin.file)
|
||||
local is_lua_file, details = get_plugin_details(common.basepath(dir) .. plugin.file)
|
||||
|
||||
plugin.valid = is_lua_file
|
||||
plugin.name = name
|
||||
|
@ -1165,8 +1164,10 @@ function core.custom_log(level, show, backtrace, fmt, ...)
|
|||
local text = string.format(fmt, ...)
|
||||
if show then
|
||||
local s = style.log[level]
|
||||
if core.status_view then
|
||||
core.status_view:show_message(s.icon, s.color, text)
|
||||
end
|
||||
end
|
||||
|
||||
local info = debug.getinfo(2, "Sl")
|
||||
local at = string.format("%s:%d", info.short_src, info.currentline)
|
||||
|
@ -1240,6 +1241,9 @@ function core.on_event(type, ...)
|
|||
elseif type == "textediting" then
|
||||
ime.on_text_editing(...)
|
||||
elseif type == "keypressed" then
|
||||
-- In some cases during IME composition input is still sent to us
|
||||
-- so we just ignore it.
|
||||
if ime.editing then return false end
|
||||
did_keymap = keymap.on_key_pressed(...)
|
||||
elseif type == "keyreleased" then
|
||||
keymap.on_key_released(...)
|
||||
|
@ -1350,7 +1354,7 @@ end
|
|||
local run_threads = coroutine.wrap(function()
|
||||
while true do
|
||||
local max_time = 1 / config.fps - 0.004
|
||||
local need_more_work = false
|
||||
local minimal_time_to_wake = math.huge
|
||||
|
||||
for k, thread in pairs(core.threads) do
|
||||
-- run thread
|
||||
|
@ -1364,48 +1368,72 @@ local run_threads = coroutine.wrap(function()
|
|||
end
|
||||
elseif wait then
|
||||
thread.wake = system.get_time() + wait
|
||||
minimal_time_to_wake = math.min(minimal_time_to_wake, wait)
|
||||
else
|
||||
need_more_work = true
|
||||
minimal_time_to_wake = 0
|
||||
end
|
||||
else
|
||||
minimal_time_to_wake = math.min(minimal_time_to_wake, thread.wake - system.get_time())
|
||||
end
|
||||
|
||||
-- stop running threads if we're about to hit the end of frame
|
||||
if system.get_time() - core.frame_start > max_time then
|
||||
coroutine.yield(true)
|
||||
coroutine.yield(0, false)
|
||||
end
|
||||
end
|
||||
|
||||
if not need_more_work then coroutine.yield(false) end
|
||||
coroutine.yield(minimal_time_to_wake, true)
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
function core.run()
|
||||
local idle_iterations = 0
|
||||
local next_step
|
||||
local last_frame_time
|
||||
local run_threads_full = 0
|
||||
while true do
|
||||
core.frame_start = system.get_time()
|
||||
local need_more_work = run_threads()
|
||||
local did_redraw = core.step()
|
||||
local time_to_wake, threads_done = run_threads()
|
||||
if threads_done then
|
||||
run_threads_full = run_threads_full + 1
|
||||
end
|
||||
local did_redraw = false
|
||||
local did_step = false
|
||||
local force_draw = core.redraw and last_frame_time and core.frame_start - last_frame_time > (1 / config.fps)
|
||||
if force_draw or not next_step or system.get_time() >= next_step then
|
||||
if core.step() then
|
||||
did_redraw = true
|
||||
last_frame_time = core.frame_start
|
||||
end
|
||||
next_step = nil
|
||||
did_step = true
|
||||
end
|
||||
if core.restart_request or core.quit_request then break end
|
||||
if not did_redraw and not need_more_work then
|
||||
idle_iterations = idle_iterations + 1
|
||||
-- do not wait of events at idle_iterations = 1 to give a chance at core.step to run
|
||||
-- and set "redraw" flag.
|
||||
if idle_iterations > 1 then
|
||||
if system.window_has_focus() then
|
||||
-- keep running even with no events to make the cursor blinks
|
||||
local t = system.get_time() - core.blink_start
|
||||
|
||||
if not did_redraw then
|
||||
if system.window_has_focus() or not did_step or run_threads_full < 2 then
|
||||
local now = system.get_time()
|
||||
if not next_step then -- compute the time until the next blink
|
||||
local t = now - core.blink_start
|
||||
local h = config.blink_period / 2
|
||||
local dt = math.ceil(t / h) * h - t
|
||||
system.wait_event(dt + 1 / config.fps)
|
||||
local cursor_time_to_wake = dt + 1 / config.fps
|
||||
next_step = now + cursor_time_to_wake
|
||||
end
|
||||
if system.wait_event(math.min(next_step - now, time_to_wake)) then
|
||||
next_step = nil -- if we've recevied an event, perform a step
|
||||
end
|
||||
else
|
||||
system.wait_event()
|
||||
next_step = nil -- perform a step when we're not in focus if get we an event
|
||||
end
|
||||
end
|
||||
else
|
||||
idle_iterations = 0
|
||||
local elapsed = system.get_time() - core.frame_start
|
||||
system.sleep(math.max(0, 1 / config.fps - elapsed))
|
||||
else -- if we redrew, then make sure we only draw at most FPS/sec
|
||||
run_threads_full = 0
|
||||
local now = system.get_time()
|
||||
local elapsed = now - core.frame_start
|
||||
local next_frame = math.max(0, 1 / config.fps - elapsed)
|
||||
next_step = next_step or (now + next_frame)
|
||||
system.sleep(math.min(next_frame, time_to_wake))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1423,7 +1451,7 @@ end
|
|||
|
||||
function core.on_error(err)
|
||||
-- write error to file
|
||||
local fp = io.open(USERDIR .. "/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()
|
||||
|
@ -1437,4 +1465,3 @@ end
|
|||
|
||||
|
||||
return core
|
||||
|
||||
|
|
|
@ -37,17 +37,38 @@ local modkey_map = modkeys_os.map
|
|||
local modkeys = modkeys_os.keys
|
||||
|
||||
|
||||
---Normalizes a stroke sequence to follow the modkeys table
|
||||
---@param stroke string
|
||||
---@return string
|
||||
local function normalize_stroke(stroke)
|
||||
local stroke_table = {}
|
||||
for key in stroke:gmatch("[^+]+") do
|
||||
table.insert(stroke_table, key)
|
||||
end
|
||||
table.sort(stroke_table, function(a, b)
|
||||
if a == b then return false end
|
||||
for _, mod in ipairs(modkeys) do
|
||||
if a == mod or b == mod then
|
||||
return a == mod
|
||||
end
|
||||
end
|
||||
return a < b
|
||||
end)
|
||||
return table.concat(stroke_table, "+")
|
||||
end
|
||||
|
||||
|
||||
---Generates a stroke sequence including currently pressed mod keys.
|
||||
---@param key string
|
||||
---@return string
|
||||
local function key_to_stroke(key)
|
||||
local stroke = ""
|
||||
local keys = { key }
|
||||
for _, mk in ipairs(modkeys) do
|
||||
if keymap.modkeys[mk] then
|
||||
stroke = stroke .. mk .. "+"
|
||||
table.insert(keys, mk)
|
||||
end
|
||||
end
|
||||
return stroke .. key
|
||||
return normalize_stroke(table.concat(keys, "+"))
|
||||
end
|
||||
|
||||
|
||||
|
@ -76,11 +97,12 @@ end
|
|||
---@param map keymap.map
|
||||
local function remove_duplicates(map)
|
||||
for stroke, commands in pairs(map) do
|
||||
local normalized_stroke = normalize_stroke(stroke)
|
||||
if type(commands) == "string" or type(commands) == "function" then
|
||||
commands = { commands }
|
||||
end
|
||||
if keymap.map[stroke] then
|
||||
for _, registered_cmd in ipairs(keymap.map[stroke]) do
|
||||
if keymap.map[normalized_stroke] then
|
||||
for _, registered_cmd in ipairs(keymap.map[normalized_stroke]) do
|
||||
local j = 0
|
||||
for i=1, #commands do
|
||||
while commands[i + j] == registered_cmd do
|
||||
|
@ -98,11 +120,12 @@ local function remove_duplicates(map)
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
---Add bindings by replacing commands that were previously assigned to a shortcut.
|
||||
---@param map keymap.map
|
||||
function keymap.add_direct(map)
|
||||
for stroke, commands in pairs(map) do
|
||||
stroke = normalize_stroke(stroke)
|
||||
|
||||
if type(commands) == "string" or type(commands) == "function" then
|
||||
commands = { commands }
|
||||
end
|
||||
|
@ -130,6 +153,7 @@ function keymap.add(map, overwrite)
|
|||
if macos then
|
||||
stroke = stroke:gsub("%f[%a]ctrl%f[%A]", "cmd")
|
||||
end
|
||||
stroke = normalize_stroke(stroke)
|
||||
if overwrite then
|
||||
if keymap.map[stroke] then
|
||||
for _, cmd in ipairs(keymap.map[stroke]) do
|
||||
|
@ -155,6 +179,7 @@ end
|
|||
---@param shortcut string
|
||||
---@param cmd string
|
||||
function keymap.unbind(shortcut, cmd)
|
||||
shortcut = normalize_stroke(shortcut)
|
||||
remove_only(keymap.map, shortcut, cmd)
|
||||
remove_only(keymap.reverse_map, cmd, shortcut)
|
||||
end
|
||||
|
@ -180,10 +205,6 @@ end
|
|||
-- Events listening
|
||||
--------------------------------------------------------------------------------
|
||||
function keymap.on_key_pressed(k, ...)
|
||||
-- In MacOS and Windows during IME composition input is still sent to us
|
||||
-- so we just ignore it
|
||||
if PLATFORM ~= "Linux" and ime.editing then return false end
|
||||
|
||||
local mk = modkey_map[k]
|
||||
if mk then
|
||||
keymap.modkeys[mk] = true
|
||||
|
@ -390,4 +411,3 @@ keymap.add_direct {
|
|||
}
|
||||
|
||||
return keymap
|
||||
|
||||
|
|
|
@ -125,9 +125,19 @@ end
|
|||
function LogView:update()
|
||||
local item = core.log_items[#core.log_items]
|
||||
if self.last_item ~= item then
|
||||
local lh = style.font:get_height() + style.padding.y
|
||||
if 0 < self.scroll.to.y then
|
||||
local index = #core.log_items
|
||||
while index > 1 and self.last_item ~= core.log_items[index] do
|
||||
index = index - 1
|
||||
end
|
||||
local diff_index = #core.log_items - index
|
||||
self.scroll.to.y = self.scroll.to.y + diff_index * lh
|
||||
self.scroll.y = self.scroll.to.y
|
||||
else
|
||||
self.yoffset = -lh
|
||||
end
|
||||
self.last_item = item
|
||||
self.scroll.to.y = 0
|
||||
self.yoffset = -(style.font:get_height() + style.padding.y)
|
||||
end
|
||||
|
||||
local expanding = self.expanding[1]
|
||||
|
|
|
@ -9,6 +9,6 @@ modkeys.map = {
|
|||
["right alt"] = "altgr",
|
||||
}
|
||||
|
||||
modkeys.keys = { "ctrl", "alt", "altgr", "shift" }
|
||||
modkeys.keys = { "ctrl", "shift", "alt", "altgr" }
|
||||
|
||||
return modkeys
|
||||
|
|
|
@ -13,6 +13,6 @@ modkeys.map = {
|
|||
["right alt"] = "altgr",
|
||||
}
|
||||
|
||||
modkeys.keys = { "cmd", "ctrl", "alt", "option", "altgr", "shift" }
|
||||
modkeys.keys = { "ctrl", "alt", "option", "altgr", "shift", "cmd" }
|
||||
|
||||
return modkeys
|
||||
|
|
|
@ -91,7 +91,7 @@ function NagView:each_option()
|
|||
|
||||
for i = #self.options, 1, -1 do
|
||||
opt = self.options[i]
|
||||
bw = opt.font:get_width(opt.text) + 2 * BORDER_WIDTH + style.padding.x
|
||||
bw = style.font:get_width(opt.text) + 2 * BORDER_WIDTH + style.padding.x
|
||||
|
||||
ox = ox - bw - style.padding.x
|
||||
coroutine.yield(i, opt, ox,oy,bw,bh)
|
||||
|
@ -230,7 +230,7 @@ local function draw_nagview_message(self)
|
|||
renderer.draw_rect(lx,ly,uw,UNDERLINE_WIDTH, style.nagbar_text)
|
||||
end
|
||||
|
||||
common.draw_text(opt.font, style.nagbar_text, opt.text, "center", fx,fy,fw,fh)
|
||||
common.draw_text(style.font, style.nagbar_text, opt.text, "center", fx,fy,fw,fh)
|
||||
end
|
||||
|
||||
self:draw_scrollbar()
|
||||
|
@ -245,6 +245,16 @@ function NagView:draw()
|
|||
core.root_view:defer_draw(draw_nagview_message, self)
|
||||
end
|
||||
|
||||
function NagView:on_scale_change(new_scale, old_scale)
|
||||
BORDER_WIDTH = common.round(1 * new_scale)
|
||||
UNDERLINE_WIDTH = common.round(2 * new_scale)
|
||||
UNDERLINE_MARGIN = common.round(1 * new_scale)
|
||||
self.target_height = math.max(
|
||||
self:get_message_height(),
|
||||
self:get_buttons_height()
|
||||
)
|
||||
end
|
||||
|
||||
function NagView:get_message_height()
|
||||
local h = 0
|
||||
for str in string.gmatch(self.message, "(.-)\n") do
|
||||
|
|
|
@ -47,7 +47,7 @@ function Object:__tostring()
|
|||
return "Object"
|
||||
end
|
||||
|
||||
---Methamethod to allow using the object call as a constructor.
|
||||
---Metamethod to allow using the object call as a constructor.
|
||||
---@return core.object
|
||||
function Object:__call(...)
|
||||
local obj = setmetatable({}, self)
|
||||
|
|
|
@ -259,10 +259,10 @@ function RootView:on_mouse_moved(x, y, dx, dy)
|
|||
if self.dragged_divider then
|
||||
local node = self.dragged_divider
|
||||
if node.type == "hsplit" then
|
||||
x = common.clamp(x, 0, self.root_node.size.x * 0.95)
|
||||
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, 0, self.root_node.size.y * 0.95)
|
||||
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)
|
||||
|
|
|
@ -189,8 +189,9 @@ function Scrollbar:_on_mouse_pressed_normal(button, x, y, clicks)
|
|||
self.drag_start_offset = along - y
|
||||
return true
|
||||
elseif overlaps == "track" then
|
||||
local nr = self.normal_rect
|
||||
self.drag_start_offset = - along_size / 2
|
||||
return (y - self.normal_rect.along - along_size / 2) / self.normal_rect.along_size
|
||||
return common.clamp((y - nr.along - along_size / 2) / (nr.along_size - along_size), 0, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
-- this file is used by lite-xl to setup the Lua environment when starting
|
||||
VERSION = "2.1.1r2"
|
||||
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 SCALE
|
||||
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)
|
||||
|
||||
EXEDIR = EXEFILE:match("^(.+)[/\\][^/\\]+$")
|
||||
if MACOS_RESOURCES then
|
||||
DATADIR = MACOS_RESOURCES
|
||||
else
|
||||
local prefix = EXEDIR:match("^(.+)[/\\]bin$")
|
||||
local prefix = os.getenv('LITE_PREFIX') or EXEDIR:match("^(.+)[/\\]bin$")
|
||||
DATADIR = prefix and (prefix .. PATHSEP .. 'share' .. PATHSEP .. 'lite-xl') or (EXEDIR .. PATHSEP .. 'data')
|
||||
end
|
||||
USERDIR = (system.get_file_info(EXEDIR .. PATHSEP .. 'user') and (EXEDIR .. PATHSEP .. 'user'))
|
||||
|
@ -35,8 +35,8 @@ package.cpath =
|
|||
|
||||
package.native_plugins = {}
|
||||
package.searchers = { package.searchers[1], package.searchers[2], function(modname)
|
||||
local path = package.searchpath(modname, package.cpath)
|
||||
if not path then return nil end
|
||||
local path, err = package.searchpath(modname, package.cpath)
|
||||
if not path then return err end
|
||||
return system.load_native_plugin, path
|
||||
end }
|
||||
|
||||
|
|
|
@ -40,4 +40,3 @@ style.syntax_fonts = {}
|
|||
style.log = {}
|
||||
|
||||
return style
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ local function find(string, field)
|
|||
end
|
||||
|
||||
function syntax.get(filename, header)
|
||||
return find(common.basename(filename), "files")
|
||||
return (filename and find(filename, "files"))
|
||||
or (header and find(header, "headers"))
|
||||
or plain_text_syntax
|
||||
end
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
local core = require "core"
|
||||
local syntax = require "core.syntax"
|
||||
local config = require "core.config"
|
||||
|
||||
local tokenizer = {}
|
||||
local bad_patterns = {}
|
||||
|
||||
local function push_token(t, type, text)
|
||||
if not text or #text == 0 then return end
|
||||
type = type or "normal"
|
||||
local prev_type = t[#t-1]
|
||||
local prev_text = t[#t]
|
||||
if prev_type and (prev_type == type or prev_text:ufind("^%s*$")) then
|
||||
if prev_type and (prev_type == type or (prev_text:ufind("^%s*$") and type ~= "incomplete")) then
|
||||
t[#t-1] = type
|
||||
t[#t] = prev_text .. text
|
||||
else
|
||||
|
@ -121,15 +123,17 @@ 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
|
||||
---@param text string
|
||||
---@param state string
|
||||
function tokenizer.tokenize(incoming_syntax, text, state)
|
||||
local res = {}
|
||||
function tokenizer.tokenize(incoming_syntax, text, state, resume)
|
||||
local res
|
||||
local i = 1
|
||||
|
||||
if #incoming_syntax.patterns == 0 then
|
||||
|
@ -137,6 +141,20 @@ function tokenizer.tokenize(incoming_syntax, text, state)
|
|||
end
|
||||
|
||||
state = state or string.char(0)
|
||||
|
||||
if resume then
|
||||
res = resume.res
|
||||
-- Remove "incomplete" tokens
|
||||
while res[#res-1] == "incomplete" do
|
||||
table.remove(res, #res)
|
||||
table.remove(res, #res)
|
||||
end
|
||||
i = resume.i
|
||||
state = resume.state
|
||||
end
|
||||
|
||||
res = res or {}
|
||||
|
||||
-- incoming_syntax : the parent syntax of the file.
|
||||
-- state : a string of bytes representing syntax state (see above)
|
||||
|
||||
|
@ -195,9 +213,11 @@ function tokenizer.tokenize(incoming_syntax, text, state)
|
|||
-- Remove '^' from the beginning of the pattern
|
||||
if type(target) == "table" then
|
||||
target[p_idx] = code:usub(2)
|
||||
code = target[p_idx]
|
||||
else
|
||||
p.pattern = p.pattern and code:usub(2)
|
||||
p.regex = p.regex and code:usub(2)
|
||||
code = p.pattern or p.regex
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -245,8 +265,22 @@ function tokenizer.tokenize(incoming_syntax, text, state)
|
|||
end
|
||||
|
||||
local text_len = text:ulen()
|
||||
if text_len ~= nil then
|
||||
while i <= text_len do
|
||||
local start_time = system.get_time()
|
||||
local starting_i = i
|
||||
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
|
||||
if system.get_time() - start_time > 0.5 / config.fps then
|
||||
-- We're out of time
|
||||
push_token(res, "incomplete", string.usub(text, i))
|
||||
return res, string.char(0), {
|
||||
res = res,
|
||||
i = i,
|
||||
state = state
|
||||
}
|
||||
end
|
||||
end
|
||||
-- continue trying to match the end pattern of a pair if we have a state set
|
||||
if current_pattern_idx > 0 then
|
||||
local p = current_syntax.patterns[current_pattern_idx]
|
||||
|
@ -284,13 +318,15 @@ function tokenizer.tokenize(incoming_syntax, text, state)
|
|||
-- General end of syntax check. Applies in the case where
|
||||
-- we're ending early in the middle of a delimiter, or
|
||||
-- just normally, upon finding a token.
|
||||
if subsyntax_info then
|
||||
while subsyntax_info do
|
||||
local s, e = find_text(text, subsyntax_info, i, true, true)
|
||||
if s then
|
||||
push_token(res, subsyntax_info.type, text:usub(i, e))
|
||||
-- On finding unescaped delimiter, pop it.
|
||||
pop_subsyntax()
|
||||
i = e + 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -299,6 +335,14 @@ function tokenizer.tokenize(incoming_syntax, text, state)
|
|||
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
|
||||
|
@ -312,6 +356,7 @@ function tokenizer.tokenize(incoming_syntax, text, state)
|
|||
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
|
||||
|
@ -327,6 +372,7 @@ function tokenizer.tokenize(incoming_syntax, text, state)
|
|||
i = find_results[2] + 1
|
||||
matched = true
|
||||
break
|
||||
::continue::
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -336,7 +382,6 @@ function tokenizer.tokenize(incoming_syntax, text, state)
|
|||
i = i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return res, state
|
||||
end
|
||||
|
|
|
@ -212,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 = {}
|
||||
|
||||
|
@ -261,6 +263,7 @@ local function update_suggestions()
|
|||
end
|
||||
end
|
||||
suggestions_idx = 1
|
||||
suggestions_offset = 1
|
||||
end
|
||||
|
||||
local function get_partial_symbol()
|
||||
|
@ -276,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
|
||||
|
||||
|
@ -287,38 +292,47 @@ local function get_suggestions_rect(av)
|
|||
local font = av:get_font()
|
||||
local th = font:get_height()
|
||||
|
||||
local ah = config.plugins.autocomplete.max_height
|
||||
|
||||
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 _, s in ipairs(suggestions) do
|
||||
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
|
||||
|
||||
local ah = config.plugins.autocomplete.max_height
|
||||
|
||||
local max_items = #suggestions
|
||||
if max_items > ah then
|
||||
max_items = ah
|
||||
end
|
||||
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_width,
|
||||
max_items * (th + style.padding.y) + style.padding.y
|
||||
end
|
||||
|
||||
|
@ -446,16 +460,29 @@ local function draw_suggestions_box(av)
|
|||
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 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
|
||||
break
|
||||
end
|
||||
local s = suggestions[i]
|
||||
|
||||
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 + style.padding.x, y, rw, lh)
|
||||
-- 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 - style.padding.x, lh)
|
||||
|
@ -631,7 +658,6 @@ end
|
|||
command.add(predicate, {
|
||||
["autocomplete:complete"] = function(dv)
|
||||
local doc = dv.doc
|
||||
local line, col = doc:get_selection()
|
||||
local item = suggestions[suggestions_idx]
|
||||
local text = item.text
|
||||
local inserted = false
|
||||
|
@ -640,19 +666,47 @@ command.add(predicate, {
|
|||
end
|
||||
if not inserted then
|
||||
local current_partial = get_partial_symbol()
|
||||
doc:insert(line, col, text)
|
||||
doc:remove(line, col, line, col - #current_partial)
|
||||
doc:set_selection(line, col + #text - #current_partial)
|
||||
local sz = #current_partial
|
||||
|
||||
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
|
||||
local j = sz - i
|
||||
local subline = line:sub(n - j, n)
|
||||
local subpartial = current_partial:sub(i, -1)
|
||||
if subpartial == subline then
|
||||
doc:remove(line1, col1, line2, n - j)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
doc:text_input(item.text)
|
||||
end
|
||||
reset_suggestions()
|
||||
end,
|
||||
|
||||
["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()
|
||||
|
|
|
@ -46,8 +46,8 @@ end
|
|||
local function check_prompt_reload(doc)
|
||||
if doc and doc.deferred_reload then
|
||||
core.nag_view:show("File Changed", doc.filename .. " has changed. Reload this file?", {
|
||||
{ font = style.font, text = "Yes", default_yes = true },
|
||||
{ font = style.font, text = "No" , default_no = true }
|
||||
{ text = "Yes", default_yes = true },
|
||||
{ text = "No", default_no = true }
|
||||
}, function(item)
|
||||
if item.text == "Yes" then reload_doc(doc) end
|
||||
doc.deferred_reload = false
|
||||
|
@ -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
|
||||
|
|
|
@ -4,6 +4,7 @@ local command = require "core.command"
|
|||
local keymap = require "core.keymap"
|
||||
local ContextMenu = require "core.contextmenu"
|
||||
local RootView = require "core.rootview"
|
||||
local config = require "core.config"
|
||||
|
||||
local menu = ContextMenu()
|
||||
local on_view_mouse_pressed = RootView.on_view_mouse_pressed
|
||||
|
@ -61,18 +62,24 @@ keymap.add { ["up"] = "context:focus-previous" }
|
|||
keymap.add { ["down"] = "context:focus-next" }
|
||||
keymap.add { ["escape"] = "context:hide" }
|
||||
|
||||
if require("plugins.scale") then
|
||||
menu:register("core.docview", {
|
||||
|
||||
local cmds = {
|
||||
{ text = "Cut", command = "doc:cut" },
|
||||
{ text = "Copy", command = "doc:copy" },
|
||||
{ text = "Paste", command = "doc:paste" },
|
||||
{ text = "Font +", command = "scale:increase" },
|
||||
{ text = "Font -", command = "scale:decrease" },
|
||||
{ text = "Font Reset", command = "scale:reset" },
|
||||
ContextMenu.DIVIDER,
|
||||
{ text = "Find", command = "find-replace:find" },
|
||||
{ text = "Replace", command = "find-replace:replace" }
|
||||
})
|
||||
}
|
||||
|
||||
if config.plugins.scale ~= false and require("plugins.scale") then
|
||||
table.move(cmds, 4, 6, 7)
|
||||
cmds[4] = { text = "Font +", command = "scale:increase" }
|
||||
cmds[5] = { text = "Font -", command = "scale:decrease" }
|
||||
cmds[6] = { text = "Font Reset", command = "scale:reset" }
|
||||
end
|
||||
|
||||
menu:register("core.docview", cmds)
|
||||
|
||||
|
||||
return menu
|
||||
|
|
|
@ -243,7 +243,7 @@ local function detect_indent_stat(doc)
|
|||
local max_lines = auto_detect_max_lines
|
||||
for i, text in get_non_empty_lines(doc.syntax, doc.lines) do
|
||||
local spaces = text:match("^ +")
|
||||
if spaces then table.insert(stat, spaces:len()) end
|
||||
if spaces and #spaces > 1 then table.insert(stat, #spaces) end
|
||||
local tabs = text:match("^\t+")
|
||||
if tabs then tab_count = tab_count + 1 end
|
||||
-- if nothing found for first lines try at least 4 more times
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
local style = require "core.style"
|
||||
local DocView = require "core.docview"
|
||||
local common = require "core.common"
|
||||
local command = require "core.command"
|
||||
local config = require "core.config"
|
||||
local Highlighter = require "core.doc.highlighter"
|
||||
|
||||
config.plugins.drawwhitespace = common.merge({
|
||||
enabled = true,
|
||||
enabled = false,
|
||||
show_leading = true,
|
||||
show_trailing = true,
|
||||
show_middle = true,
|
||||
|
@ -41,7 +42,7 @@ config.plugins.drawwhitespace = common.merge({
|
|||
description = "Disable or enable the drawing of white spaces.",
|
||||
path = "enabled",
|
||||
type = "toggle",
|
||||
default = true
|
||||
default = false
|
||||
},
|
||||
{
|
||||
label = "Show Leading",
|
||||
|
@ -303,3 +304,18 @@ function DocView:draw_line_text(idx, x, y)
|
|||
|
||||
return draw_line_text(self, idx, x, y)
|
||||
end
|
||||
|
||||
|
||||
command.add(nil, {
|
||||
["draw-whitespace:toggle"] = function()
|
||||
config.plugins.drawwhitespace.enabled = not config.plugins.drawwhitespace.enabled
|
||||
end,
|
||||
|
||||
["draw-whitespace:disable"] = function()
|
||||
config.plugins.drawwhitespace.enabled = false
|
||||
end,
|
||||
|
||||
["draw-whitespace:enable"] = function()
|
||||
config.plugins.drawwhitespace.enabled = true
|
||||
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 = { "/*", "*/" },
|
||||
|
@ -14,9 +15,9 @@ syntax.add {
|
|||
{ pattern = { "/%*", "%*/" }, type = "comment" },
|
||||
{ pattern = { '"', '"', '\\' }, type = "string" },
|
||||
{ pattern = { "'", "'", '\\' }, type = "string" },
|
||||
{ pattern = "0x%x+", type = "number" },
|
||||
{ pattern = "0x%x+[%x']*", type = "number" },
|
||||
{ pattern = "%d+[%d%.'eE]*f?", type = "number" },
|
||||
{ pattern = "%.?%d+f?", type = "number" },
|
||||
{ pattern = "%.?%d+[%d']*f?", type = "number" },
|
||||
{ pattern = "[%+%-=/%*%^%%<>!~|:&]", type = "operator" },
|
||||
{ pattern = "##", type = "operator" },
|
||||
{ pattern = "struct%s()[%a_][%w_]*", type = {"keyword", "keyword2"} },
|
||||
|
|
|
@ -1,6 +1,56 @@
|
|||
-- mod-version:3
|
||||
local syntax = require "core.syntax"
|
||||
|
||||
-- Regex pattern explanation:
|
||||
-- This will match / and will look ahead for something that looks like a regex.
|
||||
--
|
||||
-- (?!/) Don't match empty regexes.
|
||||
--
|
||||
-- (?>...) this is using an atomic group to minimize backtracking, as that'd
|
||||
-- cause "Catastrophic Backtracking" in some cases.
|
||||
--
|
||||
-- [^\\[\/]++ will match anything that's isn't an escape, a start of character
|
||||
-- class or an end of pattern, without backtracking (the second +).
|
||||
--
|
||||
-- \\. will match anything that's escaped.
|
||||
--
|
||||
-- \[(?:[^\\\]++]|\\.)*+\] will match character classes.
|
||||
--
|
||||
-- /[gmiyuvsd]*\s*[\n,;\)\]\}\.]) will match the end of pattern delimiter, optionally
|
||||
-- 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/Vx5L5V/1
|
||||
-- Note that it has a couple of changes to make it work on that platform.
|
||||
local regex_pattern = {
|
||||
[=[\/(?=(?!\/)(?:(?>[^\\[\/]++|\\.|\[(?:[^\\\]]++|\\.)*+\])*+)++\/[gmiyuvsd]*\s*(?:[\n,;\)\]\}\.]|\/[\/*]))()]=],
|
||||
"/()[gmiyuvsd]*", "\\"
|
||||
}
|
||||
|
||||
-- For the moment let's not actually differentiate the insides of the regex,
|
||||
-- as this will need new token types...
|
||||
local inner_regex_syntax = {
|
||||
patterns = {
|
||||
{ pattern = "%(()%?[:!=><]", type = { "string", "string" } },
|
||||
{ pattern = "[.?+*%(%)|]", type = "string" },
|
||||
{ pattern = "{%d*,?%d*}", type = "string" },
|
||||
{ regex = { [=[\[()\^?]=], [=[(?:\]|(?=\n))()]=], "\\" },
|
||||
type = { "string", "string" },
|
||||
syntax = { -- Inside character class
|
||||
patterns = {
|
||||
{ pattern = "\\\\", type = "string" },
|
||||
{ pattern = "\\%]", type = "string" },
|
||||
{ pattern = "[^%]\n]", type = "string" }
|
||||
},
|
||||
symbols = {}
|
||||
}
|
||||
},
|
||||
{ regex = "\\/", type = "string" },
|
||||
{ regex = "[^/\n]", type = "string" },
|
||||
},
|
||||
symbols = {}
|
||||
}
|
||||
|
||||
syntax.add {
|
||||
name = "JavaScript",
|
||||
files = { "%.js$", "%.json$", "%.cson$", "%.mjs$", "%.cjs$" },
|
||||
|
@ -9,13 +59,14 @@ syntax.add {
|
|||
patterns = {
|
||||
{ pattern = "//.*", type = "comment" },
|
||||
{ pattern = { "/%*", "%*/" }, type = "comment" },
|
||||
{ pattern = { '/[^= ]', '/', '\\' },type = "string" },
|
||||
{ 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?", type = "number" },
|
||||
{ pattern = "-?%d+[%d%.eE_n]*", type = "number" },
|
||||
{ pattern = "-?%.?%d+", type = "number" },
|
||||
-- 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" },
|
||||
|
@ -42,6 +93,7 @@ syntax.add {
|
|||
["get"] = "keyword",
|
||||
["if"] = "keyword",
|
||||
["import"] = "keyword",
|
||||
["from"] = "keyword",
|
||||
["in"] = "keyword",
|
||||
["of"] = "keyword",
|
||||
["instanceof"] = "keyword",
|
||||
|
|
|
@ -3,25 +3,6 @@ local syntax = require "core.syntax"
|
|||
local style = require "core.style"
|
||||
local core = require "core"
|
||||
|
||||
local initial_color = style.syntax["keyword2"]
|
||||
|
||||
-- Add 3 type of font styles for use on markdown files
|
||||
for _, attr in pairs({"bold", "italic", "bold_italic"}) do
|
||||
local attributes = {}
|
||||
if attr ~= "bold_italic" then
|
||||
attributes[attr] = true
|
||||
else
|
||||
attributes["bold"] = true
|
||||
attributes["italic"] = true
|
||||
end
|
||||
style.syntax_fonts["markdown_"..attr] = style.code_font:copy(
|
||||
style.code_font:get_size(),
|
||||
attributes
|
||||
)
|
||||
-- also add a color for it
|
||||
style.syntax["markdown_"..attr] = style.syntax["keyword2"]
|
||||
end
|
||||
|
||||
local in_squares_match = "^%[%]"
|
||||
local in_parenthesis_match = "^%(%)"
|
||||
|
||||
|
@ -224,14 +205,64 @@ syntax.add {
|
|||
|
||||
-- Adjust the color on theme changes
|
||||
core.add_thread(function()
|
||||
while true do
|
||||
if initial_color ~= style.syntax["keyword2"] then
|
||||
for _, attr in pairs({"bold", "italic", "bold_italic"}) do
|
||||
local custom_fonts = { bold = {font = nil, color = nil}, italic = {}, bold_italic = {} }
|
||||
local initial_color
|
||||
local last_code_font
|
||||
|
||||
local function set_font(attr)
|
||||
local attributes = {}
|
||||
if attr ~= "bold_italic" then
|
||||
attributes[attr] = true
|
||||
else
|
||||
attributes["bold"] = true
|
||||
attributes["italic"] = true
|
||||
end
|
||||
local font = style.code_font:copy(
|
||||
style.code_font:get_size(),
|
||||
attributes
|
||||
)
|
||||
custom_fonts[attr].font = font
|
||||
style.syntax_fonts["markdown_"..attr] = font
|
||||
end
|
||||
|
||||
local function set_color(attr)
|
||||
custom_fonts[attr].color = style.syntax["keyword2"]
|
||||
style.syntax["markdown_"..attr] = style.syntax["keyword2"]
|
||||
end
|
||||
|
||||
-- Add 3 type of font styles for use on markdown files
|
||||
for attr, _ in pairs(custom_fonts) do
|
||||
-- Only set it if the font wasn't manually customized
|
||||
if not style.syntax_fonts["markdown_"..attr] then
|
||||
set_font(attr)
|
||||
end
|
||||
|
||||
-- Only set it if the color wasn't manually customized
|
||||
if not style.syntax["markdown_"..attr] then
|
||||
set_color(attr)
|
||||
end
|
||||
end
|
||||
|
||||
while true do
|
||||
if last_code_font ~= style.code_font then
|
||||
last_code_font = style.code_font
|
||||
for attr, _ in pairs(custom_fonts) do
|
||||
-- Only set it if the font wasn't manually customized
|
||||
if style.syntax_fonts["markdown_"..attr] == custom_fonts[attr].font then
|
||||
set_font(attr)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if initial_color ~= style.syntax["keyword2"] then
|
||||
initial_color = style.syntax["keyword2"]
|
||||
for attr, _ in pairs(custom_fonts) do
|
||||
-- Only set it if the color wasn't manually customized
|
||||
if style.syntax["markdown_"..attr] == custom_fonts[attr].color then
|
||||
set_color(attr)
|
||||
end
|
||||
end
|
||||
end
|
||||
coroutine.yield(1)
|
||||
end
|
||||
end)
|
||||
|
||||
|
|
|
@ -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" },
|
||||
|
|
|
@ -79,8 +79,6 @@ end
|
|||
|
||||
local draw_overlay = DocView.draw_overlay
|
||||
function DocView:draw_overlay(...)
|
||||
draw_overlay(self, ...)
|
||||
|
||||
if
|
||||
type(config.plugins.lineguide) == "table"
|
||||
and
|
||||
|
@ -106,6 +104,8 @@ function DocView:draw_overlay(...)
|
|||
end
|
||||
end
|
||||
end
|
||||
-- everything else like the cursor above the line guides
|
||||
draw_overlay(self, ...)
|
||||
end
|
||||
|
||||
command.add(nil, {
|
||||
|
|
|
@ -219,7 +219,7 @@ function LineWrapping.draw_guide(docview)
|
|||
end
|
||||
|
||||
function LineWrapping.update_docview_breaks(docview)
|
||||
local x,y,w,h = docview.v_scrollbar:get_thumb_rect()
|
||||
local w = docview.v_scrollbar.expanded_size or style.expanded_scrollbar_size
|
||||
local width = (type(config.plugins.linewrapping.width_override) == "function" and config.plugins.linewrapping.width_override(docview))
|
||||
or config.plugins.linewrapping.width_override or (docview.size.x - docview:get_gutter_width() - w)
|
||||
if (not docview.wrapped_settings or docview.wrapped_settings.width == nil or width ~= docview.wrapped_settings.width) then
|
||||
|
@ -310,7 +310,7 @@ local function get_line_col_from_index_and_x(docview, idx, x)
|
|||
end
|
||||
|
||||
|
||||
local open_files = {}
|
||||
local open_files = setmetatable({ }, { __mode = "k" })
|
||||
|
||||
local old_doc_insert = Doc.raw_insert
|
||||
function Doc:raw_insert(line, col, text, undo_stack, time)
|
||||
|
@ -485,7 +485,7 @@ local old_draw_line_body = DocView.draw_line_body
|
|||
function DocView:draw_line_body(line, x, y)
|
||||
if not self.wrapped_settings then return old_draw_line_body(self, line, x, y) end
|
||||
local lh = self:get_line_height()
|
||||
local idx0 = get_line_idx_col_count(self, line)
|
||||
local idx0, _, count = get_line_idx_col_count(self, line)
|
||||
for lidx, line1, col1, line2, col2 in self.doc:get_selections(true) do
|
||||
if line >= line1 and line <= line2 then
|
||||
if line1 ~= line then col1 = 1 end
|
||||
|
@ -493,12 +493,14 @@ function DocView:draw_line_body(line, x, y)
|
|||
if col1 ~= col2 then
|
||||
local idx1, ncol1 = get_line_idx_col_count(self, line, col1)
|
||||
local idx2, ncol2 = get_line_idx_col_count(self, line, col2)
|
||||
local start = 0
|
||||
for i = idx1, idx2 do
|
||||
local x1, x2 = x + (idx1 == i and self:get_col_x_offset(line1, col1) or 0)
|
||||
if idx2 == i then
|
||||
x2 = x + self:get_col_x_offset(line, col2)
|
||||
else
|
||||
x2 = x + self:get_col_x_offset(line, get_idx_line_length(self, i, line) + 1, true)
|
||||
start = start + get_idx_line_length(self, i, line)
|
||||
x2 = x + self:get_col_x_offset(line, start + 1, true)
|
||||
end
|
||||
renderer.draw_rect(x1, y + (i - idx0) * lh, x2 - x1, lh, style.selection)
|
||||
end
|
||||
|
@ -514,7 +516,6 @@ function DocView:draw_line_body(line, x, y)
|
|||
end
|
||||
end
|
||||
if draw_highlight then
|
||||
local _, _, count = get_line_idx_col_count(self, line)
|
||||
for i=1,count do
|
||||
self:draw_line_highlight(x + self.scroll.x, y + lh * (i - 1))
|
||||
end
|
||||
|
|
|
@ -25,11 +25,16 @@ local function set_scale(scale)
|
|||
scale = common.clamp(scale, 0.2, 6)
|
||||
|
||||
-- save scroll positions
|
||||
local scrolls = {}
|
||||
local v_scrolls = {}
|
||||
local h_scrolls = {}
|
||||
for _, view in ipairs(core.root_view.root_node:get_children()) do
|
||||
local n = view:get_scrollable_size()
|
||||
if n ~= math.huge and not view:is(CommandView) and n > view.size.y then
|
||||
scrolls[view] = view.scroll.y / (n - view.size.y)
|
||||
if n ~= math.huge and n > view.size.y then
|
||||
v_scrolls[view] = view.scroll.y / (n - view.size.y)
|
||||
end
|
||||
local hn = view:get_h_scrollable_size()
|
||||
if hn ~= math.huge and hn > view.size.x then
|
||||
h_scrolls[view] = view.scroll.x / (hn - view.size.x)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -43,6 +48,7 @@ local function set_scale(scale)
|
|||
style.padding.y = style.padding.y * s
|
||||
style.divider_size = style.divider_size * s
|
||||
style.scrollbar_size = style.scrollbar_size * s
|
||||
style.expanded_scrollbar_size = style.expanded_scrollbar_size * s
|
||||
style.caret_width = style.caret_width * s
|
||||
style.tab_width = style.tab_width * s
|
||||
|
||||
|
@ -58,10 +64,14 @@ local function set_scale(scale)
|
|||
end
|
||||
|
||||
-- restore scroll positions
|
||||
for view, n in pairs(scrolls) do
|
||||
for view, n in pairs(v_scrolls) do
|
||||
view.scroll.y = n * (view:get_scrollable_size() - view.size.y)
|
||||
view.scroll.to.y = view.scroll.y
|
||||
end
|
||||
for view, hn in pairs(h_scrolls) do
|
||||
view.scroll.x = hn * (view:get_h_scrollable_size() - view.size.x)
|
||||
view.scroll.to.x = view.scroll.x
|
||||
end
|
||||
|
||||
core.redraw = true
|
||||
end
|
||||
|
|
|
@ -24,7 +24,7 @@ local tooltip_alpha_rate = 1
|
|||
|
||||
local function get_depth(filename)
|
||||
local n = 1
|
||||
for sep in filename:gmatch("[\\/]") do
|
||||
for _ in filename:gmatch(PATHSEP) do
|
||||
n = n + 1
|
||||
end
|
||||
return n
|
||||
|
@ -83,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
|
||||
|
@ -518,15 +518,19 @@ local function is_primary_project_folder(path)
|
|||
return core.project_dir == path
|
||||
end
|
||||
|
||||
menu:register(function() return view.hovered_item end, {
|
||||
|
||||
local function treeitem() return view.hovered_item or view.selected_item end
|
||||
|
||||
|
||||
menu:register(function() return core.active_view:is(TreeView) and treeitem() end, {
|
||||
{ text = "Open in System", command = "treeview:open-in-system" },
|
||||
ContextMenu.DIVIDER
|
||||
})
|
||||
|
||||
menu:register(
|
||||
function()
|
||||
return view.hovered_item
|
||||
and not is_project_folder(view.hovered_item.abs_filename)
|
||||
local item = treeitem()
|
||||
return core.active_view:is(TreeView) and item and not is_project_folder(item.abs_filename)
|
||||
end,
|
||||
{
|
||||
{ text = "Rename", command = "treeview:rename" },
|
||||
|
@ -536,7 +540,8 @@ menu:register(
|
|||
|
||||
menu:register(
|
||||
function()
|
||||
return view.hovered_item and view.hovered_item.type == "dir"
|
||||
local item = treeitem()
|
||||
return core.active_view:is(TreeView) and item and item.type == "dir"
|
||||
end,
|
||||
{
|
||||
{ text = "New File", command = "treeview:new-file" },
|
||||
|
@ -546,9 +551,10 @@ menu:register(
|
|||
|
||||
menu:register(
|
||||
function()
|
||||
return view.hovered_item
|
||||
and not is_primary_project_folder(view.hovered_item.abs_filename)
|
||||
and is_project_folder(view.hovered_item.abs_filename)
|
||||
local item = treeitem()
|
||||
return core.active_view:is(TreeView) and item
|
||||
and not is_primary_project_folder(item.abs_filename)
|
||||
and is_project_folder(item.abs_filename)
|
||||
end,
|
||||
{
|
||||
{ text = "Remove directory", command = "treeview:remove-project-directory" },
|
||||
|
@ -589,7 +595,10 @@ command.add(nil, {
|
|||
end
|
||||
})
|
||||
|
||||
command.add(TreeView, {
|
||||
command.add(
|
||||
function()
|
||||
return not menu.show_context_menu and core.active_view:extends(TreeView), TreeView
|
||||
end, {
|
||||
["treeview:next"] = function()
|
||||
local item, _, item_y = view:get_next(view.selected_item)
|
||||
view:set_selection(item, item_y)
|
||||
|
@ -660,33 +669,24 @@ command.add(TreeView, {
|
|||
})
|
||||
|
||||
|
||||
local function treeitem() return view.hovered_item or view.selected_item end
|
||||
|
||||
|
||||
command.add(
|
||||
function()
|
||||
local item = treeitem()
|
||||
return item ~= nil
|
||||
and (
|
||||
core.active_view == view or core.active_view == menu
|
||||
or (view.toolbar and core.active_view == view.toolbar)
|
||||
-- sometimes the context menu is shown on top of statusbar
|
||||
or core.active_view == core.status_view
|
||||
), item
|
||||
return item ~= nil and (core.active_view == view or menu.show_context_menu), item
|
||||
end, {
|
||||
["treeview:delete"] = function(item)
|
||||
local filename = item.abs_filename
|
||||
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"
|
||||
-- Ask before deleting
|
||||
local opt = {
|
||||
{ font = style.font, text = "Yes", default_yes = true },
|
||||
{ font = style.font, text = "No" , default_no = true }
|
||||
{ text = "Yes", default_yes = true },
|
||||
{ text = "No", default_no = true }
|
||||
}
|
||||
core.nag_view:show(
|
||||
string.format("Delete %s", file_type),
|
||||
|
@ -724,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
|
||||
|
@ -754,7 +754,7 @@ 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("")
|
||||
|
@ -776,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,
|
||||
|
@ -802,7 +802,8 @@ command.add(
|
|||
local projectsearch = pcall(require, "plugins.projectsearch")
|
||||
if projectsearch then
|
||||
menu:register(function()
|
||||
return view.hovered_item and view.hovered_item.type == "dir"
|
||||
local item = treeitem()
|
||||
return item and item.type == "dir"
|
||||
end, {
|
||||
{ text = "Find in directory", command = "treeview:search-in-directory" }
|
||||
})
|
||||
|
|
|
@ -8,7 +8,7 @@ local Doc = require "core.doc"
|
|||
---@field enabled boolean
|
||||
---@field trim_empty_end_lines boolean
|
||||
config.plugins.trimwhitespace = common.merge({
|
||||
enabled = true,
|
||||
enabled = false,
|
||||
trim_empty_end_lines = false,
|
||||
config_spec = {
|
||||
name = "Trim Whitespace",
|
||||
|
@ -17,7 +17,7 @@ config.plugins.trimwhitespace = common.merge({
|
|||
description = "Disable or enable the trimming of white spaces by default.",
|
||||
path = "enabled",
|
||||
type = "toggle",
|
||||
default = true
|
||||
default = false
|
||||
},
|
||||
{
|
||||
label = "Trim Empty End Lines",
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
@ -83,7 +83,8 @@ local function save_view(view)
|
|||
filename = view.doc.filename,
|
||||
selection = { view.doc:get_selection() },
|
||||
scroll = { x = view.scroll.to.x, y = view.scroll.to.y },
|
||||
text = not view.doc.filename and view.doc:get_text(1, 1, math.huge, math.huge)
|
||||
crlf = view.doc.crlf,
|
||||
text = view.doc.new_file and view.doc:get_text(1, 1, math.huge, math.huge)
|
||||
}
|
||||
end
|
||||
if mt == LogView then return end
|
||||
|
@ -106,7 +107,6 @@ local function load_view(t)
|
|||
if not t.filename then
|
||||
-- document not associated to a file
|
||||
dv = DocView(core.open_doc())
|
||||
if t.text then dv.doc:insert(1, 1, t.text) end
|
||||
else
|
||||
-- we have a filename, try to read the file
|
||||
local ok, doc = pcall(core.open_doc, t.filename)
|
||||
|
@ -114,9 +114,11 @@ local function load_view(t)
|
|||
dv = DocView(doc)
|
||||
end
|
||||
end
|
||||
-- doc view "dv" can be nil here if the filename associated to the document
|
||||
-- cannot be read.
|
||||
if dv and dv.doc then
|
||||
if dv.doc.new_file and t.text then
|
||||
dv.doc:insert(1, 1, t.text)
|
||||
dv.doc.crlf = t.crlf
|
||||
end
|
||||
dv.doc:set_selection(table.unpack(t.selection))
|
||||
dv.last_line1, dv.last_col1, dv.last_line2, dv.last_col2 = dv.doc:get_selection()
|
||||
dv.scroll.x, dv.scroll.to.x = t.scroll.x, t.scroll.x
|
||||
|
|
|
@ -45,10 +45,14 @@ function dirmonitor:unwatch(fd_or_path) end
|
|||
---edited, removed or added. A file descriptor will be passed to the
|
||||
---callback in "multiple" mode or a path in "single" mode.
|
||||
---
|
||||
---If an error occurred during the callback execution, the error callback will be called with the error object.
|
||||
---This callback should not manipulate coroutines to avoid deadlocks.
|
||||
---
|
||||
---@param callback dirmonitor.callback
|
||||
---@param error_callback fun(error: any): nil
|
||||
---
|
||||
---@return boolean? changes True when changes were detected.
|
||||
function dirmonitor:check(callback) end
|
||||
function dirmonitor:check(callback, error_callback) end
|
||||
|
||||
---
|
||||
---Get the working mode for the current file system monitoring backend.
|
||||
|
|
|
@ -61,10 +61,10 @@ function system.poll_event() end
|
|||
---
|
||||
---Wait until an event is triggered.
|
||||
---
|
||||
---@param timeout number Amount of seconds, also supports fractions
|
||||
---of a second, eg: 0.01
|
||||
---@param timeout? number Amount of seconds, also supports fractions
|
||||
---of a second, eg: 0.01. If not provided, waits forever.
|
||||
---
|
||||
---@return boolean status True on success or false if there was an error.
|
||||
---@return boolean status True on success or false if there was an error or if no event was received.
|
||||
function system.wait_event(timeout) end
|
||||
|
||||
---
|
||||
|
@ -107,10 +107,12 @@ function system.set_window_bordered(bordered) end
|
|||
---When then window is run borderless (without system decorations), this
|
||||
---function allows to set the size of the different regions that allow
|
||||
---for custom window management.
|
||||
---To disable custom window management, call this function without any
|
||||
---arguments
|
||||
---
|
||||
---@param title_height number
|
||||
---@param controls_width number Width of window controls (maximize,minimize and close buttons, etc).
|
||||
---@param resize_border number The amount of pixels reserved for resizing
|
||||
---@param title_height? number Height of the window decoration
|
||||
---@param controls_width? number Width of window controls (maximize,minimize and close buttons, etc).
|
||||
---@param resize_border? number The amount of pixels reserved for resizing
|
||||
function system.set_window_hit_test(title_height, controls_width, resize_border) end
|
||||
|
||||
---
|
||||
|
@ -316,9 +318,11 @@ function system.load_native_plugin(name, path) end
|
|||
---Compares two paths in the order used by TreeView.
|
||||
---
|
||||
---@param path1 string
|
||||
---@param type1 system.fileinfotype
|
||||
---@param path2 string
|
||||
---@param type2 system.fileinfotype
|
||||
---@return boolean compare_result True if path1 < path2
|
||||
function system.path_compare(path1, path2) end
|
||||
function system.path_compare(path1, type1, path2, type2) end
|
||||
|
||||
|
||||
return system
|
||||
|
|
40
meson.build
40
meson.build
|
@ -1,11 +1,10 @@
|
|||
project('lite-xl',
|
||||
['c'],
|
||||
version : '2.1.1',
|
||||
version : '2.1.4',
|
||||
license : 'MIT',
|
||||
meson_version : '>= 0.56',
|
||||
default_options : [
|
||||
'c_std=gnu11',
|
||||
'wrap_mode=nofallback'
|
||||
'c_std=gnu11'
|
||||
]
|
||||
)
|
||||
|
||||
|
@ -36,6 +35,7 @@ conf_data = configuration_data()
|
|||
conf_data.set('PROJECT_BUILD_DIR', meson.current_build_dir())
|
||||
conf_data.set('PROJECT_SOURCE_DIR', meson.current_source_dir())
|
||||
conf_data.set('PROJECT_VERSION', version)
|
||||
conf_data.set('PROJECT_ASSEMBLY_VERSION', meson.project_version() + '.0')
|
||||
|
||||
#===============================================================================
|
||||
# Compiler Settings
|
||||
|
@ -63,10 +63,6 @@ lite_cargs += '-DLITE_ARCH_TUPLE="@0@"'.format(arch_tuple)
|
|||
# Linker Settings
|
||||
#===============================================================================
|
||||
lite_link_args = []
|
||||
if cc.get_id() == 'gcc' and get_option('buildtype') == 'release'
|
||||
lite_link_args += ['-static-libgcc']
|
||||
endif
|
||||
|
||||
if host_machine.system() == 'darwin'
|
||||
lite_link_args += ['-framework', 'CoreServices', '-framework', 'Foundation']
|
||||
endif
|
||||
|
@ -87,11 +83,10 @@ if not get_option('source-only')
|
|||
'lua', # Fedora
|
||||
]
|
||||
|
||||
if get_option('use_system_lua')
|
||||
foreach lua : lua_names
|
||||
last_lua = (lua == lua_names[-1] or get_option('wrap_mode') == 'forcefallback')
|
||||
lua_dep = dependency(lua, fallback: last_lua ? ['lua', 'lua_dep'] : [], required : false,
|
||||
version: '>= 5.4',
|
||||
default_options: default_fallback_options + ['default_library=static', 'line_editing=false', 'interpreter=false']
|
||||
lua_dep = dependency(lua, required : false,
|
||||
)
|
||||
if lua_dep.found()
|
||||
break
|
||||
|
@ -104,6 +99,11 @@ if not get_option('source-only')
|
|||
lua_dep = cc.find_library('lua', required : true)
|
||||
endif
|
||||
endforeach
|
||||
else
|
||||
lua_dep = dependency('', fallback: ['lua', 'lua_dep'], required : true,
|
||||
default_options: default_fallback_options + ['default_library=static', 'line_editing=false', 'interpreter=false']
|
||||
)
|
||||
endif
|
||||
|
||||
pcre2_dep = dependency('libpcre2-8', fallback: ['pcre2', 'libpcre2_8'],
|
||||
default_options: default_fallback_options + ['default_library=static', 'grep=false', 'test=false']
|
||||
|
@ -123,6 +123,7 @@ if not get_option('source-only')
|
|||
sdl_options += 'use_atomic=enabled'
|
||||
sdl_options += 'use_threads=enabled'
|
||||
sdl_options += 'use_timers=enabled'
|
||||
sdl_options += 'with_main=true'
|
||||
# investigate if this is truly needed
|
||||
# Do not remove before https://github.com/libsdl-org/SDL/issues/5413 is released
|
||||
sdl_options += 'use_events=enabled'
|
||||
|
@ -155,12 +156,24 @@ if not get_option('source-only')
|
|||
sdl_options += 'use_video_vulkan=disabled'
|
||||
sdl_options += 'use_video_offscreen=disabled'
|
||||
sdl_options += 'use_power=disabled'
|
||||
sdl_options += 'system_iconv=disabled'
|
||||
|
||||
sdl_dep = dependency('sdl2', fallback: ['sdl2', 'sdl2_dep'],
|
||||
default_options: default_fallback_options + sdl_options
|
||||
)
|
||||
|
||||
lite_deps = [lua_dep, sdl_dep, freetype_dep, pcre2_dep, libm, libdl]
|
||||
if host_machine.system() == 'windows'
|
||||
if sdl_dep.type_name() == 'internal'
|
||||
sdlmain_dep = dependency('sdl2main', fallback: ['sdl2main_dep'])
|
||||
else
|
||||
sdlmain_dep = cc.find_library('SDL2main')
|
||||
endif
|
||||
else
|
||||
sdlmain_dep = dependency('', required: false)
|
||||
assert(not sdlmain_dep.found(), 'checking if fake dependency has been found')
|
||||
endif
|
||||
|
||||
lite_deps = [lua_dep, sdl_dep, sdlmain_dep, freetype_dep, pcre2_dep, libm, libdl]
|
||||
endif
|
||||
#===============================================================================
|
||||
# Install Configuration
|
||||
|
@ -169,6 +182,11 @@ if get_option('portable') or host_machine.system() == 'windows'
|
|||
lite_bindir = '/'
|
||||
lite_docdir = '/doc'
|
||||
lite_datadir = '/data'
|
||||
configure_file(
|
||||
input: 'resources/windows/lite-xl.exe.manifest.in',
|
||||
output: 'lite-xl.exe.manifest',
|
||||
configuration: conf_data
|
||||
)
|
||||
elif get_option('bundle') and host_machine.system() == 'darwin'
|
||||
lite_cargs += '-DMACOS_USE_BUNDLE'
|
||||
lite_bindir = 'Contents/MacOS'
|
||||
|
|
|
@ -4,3 +4,4 @@ option('portable', type : 'boolean', value : false, description: 'Portable insta
|
|||
option('renderer', type : 'boolean', value : false, description: 'Use SDL renderer')
|
||||
option('dirmonitor_backend', type : 'combo', value : '', choices : ['', 'inotify', 'fsevents', 'kqueue', 'win32', 'dummy'], description: 'define what dirmonitor backend to use')
|
||||
option('arch_tuple', type : 'string', value : '', description: 'Specify a custom architecture tuple')
|
||||
option('use_system_lua', type : 'boolean', value : false, description: 'Prefer System Lua over a the meson wrap')
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
# Resources
|
||||
|
||||
This folder contains resources that is used for building or packaging the project.
|
||||
|
||||
### Build
|
||||
|
||||
- `cross/*.txt`: Meson [cross files][1] for cross-compiling lite-xl on other platforms.
|
||||
|
||||
### Packaging
|
||||
|
||||
- `icons/icon.{icns,ico,inl,rc,svg}`: lite-xl icon in various formats.
|
||||
- `linux/com.lite_xl.LiteXL.appdata.xml`: AppStream metadata.
|
||||
- `linux/com.lite_xl.LiteXL.desktop`: Desktop file for Linux desktops.
|
||||
- `macos/dmg-cover.png`: Background image for packaging macOS DMGs.
|
||||
- `macos/Info.plist.in`: Template for generating `info.plist` on macOS. See `macos/macos-retina-display.md` for details.
|
||||
- `macos/lite-xl-dmg.py`: Configuration options for dmgbuild for packaging macOS DMGs.
|
||||
- `windows/001-lua-unicode.diff`: Patch for allowing Lua to load files with UTF-8 filenames on Windows.
|
||||
|
||||
### Development
|
||||
|
||||
- `include/lite_xl_plugin_api.h`: Native plugin API header. See the contents of `lite_xl_plugin_api.h` for more details.
|
||||
|
||||
|
||||
[1]: https://mesonbuild.com/Cross-compilation.html
|
|
@ -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
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue