Compare commits
527 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e64cab2d4 | ||
|
|
9c8cf0bc09 | ||
|
|
bafc556b00 | ||
|
|
0ec3232c81 | ||
|
|
469c1ceb07 | ||
|
|
5e80f120c9 | ||
|
|
8faa26b663 | ||
|
|
201e2fcfdb | ||
|
|
5678487a16 | ||
|
|
6646e8c311 | ||
|
|
96fc4d3280 | ||
|
|
cb3ea3fb75 | ||
|
|
787a2d1957 | ||
|
|
89e1275dda | ||
|
|
ddc927d617 | ||
|
|
c37a51c6d0 | ||
|
|
91095e8d4e | ||
|
|
d4fa7e3fd2 | ||
|
|
9204f0735c | ||
|
|
cfc32a14e0 | ||
|
|
270aa52591 | ||
|
|
99a5913391 | ||
|
|
c3d6165aff | ||
|
|
9220616bb5 | ||
|
|
eb9b4aee21 | ||
|
|
d9a7671830 | ||
|
|
353c410f0e | ||
|
|
7ca4cddc58 | ||
|
|
12543f762b | ||
|
|
ec7fabcb58 | ||
|
|
5d08f2bc5a | ||
|
|
a557b82c83 | ||
|
|
62a884cb5a | ||
|
|
88875a3375 | ||
|
|
cd547ebdaf | ||
|
|
e511d6aecf | ||
|
|
9b6148dec3 | ||
|
|
29a1aad45a | ||
|
|
a9fce727d4 | ||
|
|
9e85d2cdbd | ||
|
|
c4f430276a | ||
|
|
fdf57b6cfa | ||
|
|
0a9e76abb7 | ||
|
|
3e085e5cae | ||
|
|
73cd54e75c | ||
|
|
28b8e59b4d | ||
|
|
51b6725b91 | ||
|
|
93ca30fda0 | ||
|
|
8c222368de | ||
|
|
a3aa6b0628 | ||
|
|
d0061794dd | ||
|
|
17c8708b54 | ||
|
|
da0ddbb80d | ||
|
|
138b4b1a95 | ||
|
|
1299072ea9 | ||
|
|
bb5893f989 | ||
|
|
7b764fd7d8 | ||
|
|
ac2fc49a48 | ||
|
|
c0abf6e2c5 | ||
|
|
85ff0bac55 | ||
|
|
3671b83a9c | ||
|
|
6970bf4fc1 | ||
|
|
e5cce1b1bc | ||
|
|
faa8eca810 | ||
|
|
84bf0cbae5 | ||
|
|
a77264208e | ||
|
|
ee06db8c8f | ||
|
|
e330b43750 | ||
|
|
f5b21498bf | ||
|
|
83388ecf1c | ||
|
|
87de631af4 | ||
|
|
e4271d3945 | ||
|
|
65b8a2f97c | ||
|
|
0656154c35 | ||
|
|
b3f682144b | ||
|
|
d3c3e157c7 | ||
|
|
2534402157 | ||
|
|
ec80ba5caf | ||
|
|
26621b6336 | ||
|
|
d961e3cdf1 | ||
|
|
7ef399912b | ||
|
|
9fc789676f | ||
|
|
f01dc3d102 | ||
|
|
501bf624cc | ||
|
|
f8605688ab | ||
|
|
590a9bef2d | ||
|
|
419756d19e | ||
|
|
93ce81b355 | ||
|
|
8bfa4461b0 | ||
|
|
648feb82f8 | ||
|
|
74645e12fc | ||
|
|
71de1a0b55 | ||
|
|
694f3cb174 | ||
|
|
a2bc5073d0 | ||
|
|
3134ef7c03 | ||
|
|
8e665e27e7 | ||
|
|
e6fbf62cf9 | ||
|
|
ce8b5e33da | ||
|
|
b63b603d64 | ||
|
|
31aa6feb0c | ||
|
|
98c9e25124 | ||
|
|
bb97e1a661 | ||
|
|
a4341a5cac | ||
|
|
fe844d4f8c | ||
|
|
447cf60afb | ||
|
|
7a11f9aaff | ||
|
|
527591f651 | ||
|
|
fca6f99870 | ||
|
|
8c97f0bec7 | ||
|
|
58ee801e57 | ||
|
|
c1ce578018 | ||
|
|
464d8417f5 | ||
|
|
44bd008829 | ||
|
|
f3b7261748 | ||
|
|
5d579fee68 | ||
|
|
d7ab99013c | ||
|
|
a3a5339048 | ||
|
|
d95a23de28 | ||
|
|
744d953822 | ||
|
|
f8e5717b80 | ||
|
|
3ad2d1a309 | ||
|
|
7186222393 | ||
|
|
d66c07717c | ||
|
|
132dd7514a | ||
|
|
aca9d0f1ef | ||
|
|
eabceae6f1 | ||
|
|
3a5b05e5c6 | ||
|
|
11e5f6a1c1 | ||
|
|
bec9acdc3f | ||
|
|
37079b7388 | ||
|
|
22b7bf826b | ||
|
|
7cc71a4fdb | ||
|
|
fb28b9d36d | ||
|
|
720087f082 | ||
|
|
3bdb87d3aa | ||
|
|
e4066ba164 | ||
|
|
a0fdaabb1f | ||
|
|
38ac4318b9 | ||
|
|
e382a32ebd | ||
|
|
8074245758 | ||
|
|
f26a04216a | ||
|
|
e565d29490 | ||
|
|
947c50353d | ||
|
|
83851a61d5 | ||
|
|
893a1e3723 | ||
|
|
6bf18b6837 | ||
|
|
94857d8802 | ||
|
|
58d1e77ac1 | ||
|
|
1fbc65b007 | ||
|
|
c25c8c753d | ||
|
|
317b7b4c59 | ||
|
|
68042994e0 | ||
|
|
d00c028a0c | ||
|
|
a9e6c887f2 | ||
|
|
69f9457bda | ||
|
|
0fed54f1c3 | ||
|
|
b45fde2e5f | ||
|
|
c1010a79f9 | ||
|
|
c33154d128 | ||
|
|
c0d613c46d | ||
|
|
4f7bbee769 | ||
|
|
7a567583f2 | ||
|
|
0ac1f071cd | ||
|
|
114e7809fe | ||
|
|
4106cc61b5 | ||
|
|
7c0d6930fa | ||
|
|
1c8cc36402 | ||
|
|
4f6392ce14 | ||
|
|
c6abbf0cf7 | ||
|
|
89beda16fd | ||
|
|
6dee56d72e | ||
|
|
e4d6ab3a6e | ||
|
|
c964f9eeff | ||
|
|
7248d5bab8 | ||
|
|
42c714891a | ||
|
|
89e073bf28 | ||
|
|
490ae1c9fd | ||
|
|
2a27383682 | ||
|
|
00f8a43b0f | ||
|
|
759ac4a4c8 | ||
|
|
e66b865cd6 | ||
|
|
78bfc3341b | ||
|
|
898afb7ed7 | ||
|
|
2b01392b41 | ||
|
|
8eb12b2280 | ||
|
|
67528789ed | ||
|
|
2e86ae6556 | ||
|
|
1e6e9fa417 | ||
|
|
a27feee1be | ||
|
|
6a3e4671b6 | ||
|
|
6a8825d972 | ||
|
|
3a87f8bc31 | ||
|
|
15a041a195 | ||
|
|
891621be69 | ||
|
|
bc4444d132 | ||
|
|
56259616cb | ||
|
|
4113574a43 | ||
|
|
cef8086419 | ||
|
|
9d59203121 | ||
|
|
f426e3d764 | ||
|
|
f378411bb8 | ||
|
|
b882bcb1df | ||
|
|
8abb8f9e0e | ||
|
|
191c9e9c82 | ||
|
|
94c5fba66f | ||
|
|
86c74c7fdb | ||
|
|
9cf45468ae | ||
|
|
c2ce7d617a | ||
|
|
50c0252055 | ||
|
|
f82ff5aa76 | ||
|
|
0b5945f219 | ||
|
|
0bdb6d7e96 | ||
|
|
e78ab589b0 | ||
|
|
339bd84cf9 | ||
|
|
529760213b | ||
|
|
1c17bf82a0 | ||
|
|
200e1c016c | ||
|
|
f29e047ba2 | ||
|
|
466d4966fd | ||
|
|
8a83267ead | ||
|
|
5e8be78760 | ||
|
|
2a6870d73b | ||
|
|
ace237989c | ||
|
|
61e0678af4 | ||
|
|
27a287f8ea | ||
|
|
87b8c623c5 | ||
|
|
64b4aba6ba | ||
|
|
5c2446be67 | ||
|
|
1437df7de1 | ||
|
|
ad88042e5b | ||
|
|
f3669dfc42 | ||
|
|
efdc3ebfac | ||
|
|
2751d655e6 | ||
|
|
73ba913f59 | ||
|
|
49a373426e | ||
|
|
392fb2abad | ||
|
|
d543e8147f | ||
|
|
27dbcdd281 | ||
|
|
0dbad48d47 | ||
|
|
07170a5a39 | ||
|
|
13860a3f16 | ||
|
|
95b7a30d06 | ||
|
|
b32f3ffd84 | ||
|
|
6c54f3c804 | ||
|
|
1b08487ee9 | ||
|
|
ff3d01f2c7 | ||
|
|
10df00d62f | ||
|
|
73c19c6cbf | ||
|
|
c2959fe52d | ||
|
|
594f816702 | ||
|
|
e39dd1525d | ||
|
|
945bc7ded3 | ||
|
|
5df6f32fda | ||
|
|
d31bc8a0bd | ||
|
|
73e25fc721 | ||
|
|
5df371b20a | ||
|
|
e6e478e857 | ||
|
|
bfea3d53b3 | ||
|
|
9fa31db207 | ||
|
|
84efc13b52 | ||
|
|
607af4b8fc | ||
|
|
08060abe76 | ||
|
|
27f513e2a3 | ||
|
|
40651e9852 | ||
|
|
c6d043b42c | ||
|
|
3a3dae3d02 | ||
|
|
5c326c553c | ||
|
|
981ff34ac4 | ||
|
|
f5330cb915 | ||
|
|
dab97071c0 | ||
|
|
84056415ca | ||
|
|
9cc2e7745e | ||
|
|
cb57ceb541 | ||
|
|
0fd92a379b | ||
|
|
1a17b8907a | ||
|
|
b7ed153b14 | ||
|
|
b1163624ba | ||
|
|
59a92c33b6 | ||
|
|
55403c6e76 | ||
|
|
35171fe2b4 | ||
|
|
95158c30b7 | ||
|
|
da20a377c1 | ||
|
|
fcbb178096 | ||
|
|
553a2f9929 | ||
|
|
e5213640d7 | ||
|
|
c95da1c813 | ||
|
|
2ee290034a | ||
|
|
69a81afd09 | ||
|
|
a18ac7c504 | ||
|
|
07bd3de4fb | ||
|
|
ef955a300a | ||
|
|
19cb783e66 | ||
|
|
d2dd61f297 | ||
|
|
a769aef059 | ||
|
|
6eb6bfa25d | ||
|
|
6b916c1494 | ||
|
|
08a4b2d19a | ||
|
|
2890885157 | ||
|
|
2d65797dfc | ||
|
|
bb2fa70cd6 | ||
|
|
937e87d760 | ||
|
|
808797a48b | ||
|
|
c61f76f020 | ||
|
|
16073ea4aa | ||
|
|
3163b8687b | ||
|
|
1c1d71e2d0 | ||
|
|
e70531fcc1 | ||
|
|
12756a165f | ||
|
|
fa4b890bce | ||
|
|
c1ab1296f8 | ||
|
|
1284cf9868 | ||
|
|
b0480e1667 | ||
|
|
ca6b4c3497 | ||
|
|
1172908e41 | ||
|
|
4a8c3d719f | ||
|
|
bd732386e4 | ||
|
|
8e87bcf37b | ||
|
|
0198f135ac | ||
|
|
ff3effdb31 | ||
|
|
22d344e764 | ||
|
|
c85a8ecc7d | ||
|
|
2fec1b79af | ||
|
|
69586e6876 | ||
|
|
d2bd369144 | ||
|
|
47e8977371 | ||
|
|
71f8d09043 | ||
|
|
216afdd494 | ||
|
|
2de2c7fc9d | ||
|
|
e7eec0f328 | ||
|
|
4c3694bfa3 | ||
|
|
34d2f20e16 | ||
|
|
a78859fc2a | ||
|
|
cc98ae0ea4 | ||
|
|
6b8cb54e71 | ||
|
|
5609612473 | ||
|
|
317505484e | ||
|
|
d1f4d99c19 | ||
|
|
2e56db6475 | ||
|
|
1656cfae63 | ||
|
|
295cd6ac83 | ||
|
|
bd20cec286 | ||
|
|
115c2576cf | ||
|
|
c204b31cda | ||
|
|
07fb8c072d | ||
|
|
9210f915ca | ||
|
|
78e908c761 | ||
|
|
68733cf0c2 | ||
|
|
b231905981 | ||
|
|
a9b094bf27 | ||
|
|
3c37f13f54 | ||
|
|
196c4f7976 | ||
|
|
f378cf9ff9 | ||
|
|
ef20645447 | ||
|
|
c4a4acdc39 | ||
|
|
54a63e7689 | ||
|
|
dcdbb092c3 | ||
|
|
e87ef882d5 | ||
|
|
221fc66ca1 | ||
|
|
ec3066caee | ||
|
|
45e2b565ef | ||
|
|
ffdc90012e | ||
|
|
307c6ebb73 | ||
|
|
9fc0b7cc38 | ||
|
|
b5e8fcaf57 | ||
|
|
0967ee1b46 | ||
|
|
c16c528270 | ||
|
|
d3803fc6f3 | ||
|
|
18515111ff | ||
|
|
ea34a1688c | ||
|
|
aa5a7294df | ||
|
|
e086ba5eb4 | ||
|
|
22dc4ef997 | ||
|
|
bc648e981e | ||
|
|
51afb63e25 | ||
|
|
6871216649 | ||
|
|
94340ab1a1 | ||
|
|
3a837cf663 | ||
|
|
edebe8f7c6 | ||
|
|
3028b20a7f | ||
|
|
2752f30f21 | ||
|
|
a50e5cc733 | ||
|
|
b790dabc8c | ||
|
|
395cf59e59 | ||
|
|
6113990b50 | ||
|
|
71495f3878 | ||
|
|
b83c6023c4 | ||
|
|
2cc34efbde | ||
|
|
4090386cc3 | ||
|
|
ee9ce5fadc | ||
|
|
f7639d2537 | ||
|
|
16851d10b4 | ||
|
|
468e996ba1 | ||
|
|
86603573f0 | ||
|
|
690bd4ce5f | ||
|
|
daeea2258d | ||
|
|
8cc583e714 | ||
|
|
a29392e75a | ||
|
|
061b0c981d | ||
|
|
72b669b5db | ||
|
|
2a5c444eff | ||
|
|
0deb5df11d | ||
|
|
280f9a98c4 | ||
|
|
b05e51f2f1 | ||
|
|
9efa748e66 | ||
|
|
8932028a75 | ||
|
|
62e483a21a | ||
|
|
e2bdfbbedb | ||
|
|
f297105c25 | ||
|
|
ddc82853fc | ||
|
|
64f99ba637 | ||
|
|
1542eb14b3 | ||
|
|
5aa0040a83 | ||
|
|
c2e7ccddb4 | ||
|
|
c9d0d339eb | ||
|
|
d6aa4d26dd | ||
|
|
d0042b5891 | ||
|
|
f6f5cc2ecb | ||
|
|
38f19e21f0 | ||
|
|
b78ac44e73 | ||
|
|
19ad1a1b82 | ||
|
|
00b40df6e1 | ||
|
|
9d5966819b | ||
|
|
13ad877b2f | ||
|
|
138b85dd3c | ||
|
|
50a6a1f3dc | ||
|
|
42058034a5 | ||
|
|
3014b11422 | ||
|
|
a98f01d924 | ||
|
|
d09195097d | ||
|
|
676bff43d9 | ||
|
|
6a459427fb | ||
|
|
513b0c6597 | ||
|
|
36f51baf2b | ||
|
|
3cc3c751b4 | ||
|
|
5fbda79dbe | ||
|
|
b7ce4d04ba | ||
|
|
ec4b35ea75 | ||
|
|
e8dc75df51 | ||
|
|
febd1d5ab3 | ||
|
|
fcf4b57838 | ||
|
|
9885abc626 | ||
|
|
01f99d7f12 | ||
|
|
17e306a3c9 | ||
|
|
32eaded3af | ||
|
|
865c0fb981 | ||
|
|
645fd43339 | ||
|
|
85db664756 | ||
|
|
f4e7dcd5e8 | ||
|
|
4bc24246ab | ||
|
|
9cf14cc3a8 | ||
|
|
e64234b462 | ||
|
|
5295d956a2 | ||
|
|
a8814f0e9b | ||
|
|
883e71612c | ||
|
|
2efbe97286 | ||
|
|
cc9bb31b9c | ||
|
|
b2e27144b7 | ||
|
|
8dbafa3cd9 | ||
|
|
14bdd3819f | ||
|
|
72173533a6 | ||
|
|
0b7bf533fa | ||
|
|
b3791f7a6a | ||
|
|
3042ce13e7 | ||
|
|
ac9a9a7758 | ||
|
|
94c53e6342 | ||
|
|
eb91cfd650 | ||
|
|
3d955abd31 | ||
|
|
8f6087068e | ||
|
|
2754bd7a93 | ||
|
|
40f74656f3 | ||
|
|
9453ec4e29 | ||
|
|
74c4634da2 | ||
|
|
a8bb064557 | ||
|
|
b7809a709c | ||
|
|
2916182cdf | ||
|
|
42e3f126e4 | ||
|
|
e10df0708c | ||
|
|
46164de94a | ||
|
|
39c0250833 | ||
|
|
e5e92c8ece | ||
|
|
5f6aba8a10 | ||
|
|
e5c1d38722 | ||
|
|
835891999e | ||
|
|
729715ebfb | ||
|
|
bdc6a1fe29 | ||
|
|
931e319fbf | ||
|
|
6743eb8d1b | ||
|
|
e2aaa97a01 | ||
|
|
c2a8f4f4a3 | ||
|
|
4270ab416e | ||
|
|
d47a5c4ffe | ||
|
|
97e127a4af | ||
|
|
cfd33c802c | ||
|
|
971f52f92a | ||
|
|
71c09b1d67 | ||
|
|
d93a94322e | ||
|
|
156d3c421c | ||
|
|
7fc3fdab94 | ||
|
|
625e9efcf3 | ||
|
|
e2d43b4538 | ||
|
|
9320a548f4 | ||
|
|
4081f44a0e | ||
|
|
d21ca03e9c | ||
|
|
355c4164c9 | ||
|
|
989a0d6cd9 | ||
|
|
8a0fec0a63 | ||
|
|
d84f4387c5 | ||
|
|
75e8a6cdc0 | ||
|
|
38a9ad6a46 | ||
|
|
b99510ad4f | ||
|
|
02ecdf565e | ||
|
|
f116e52228 | ||
|
|
3ff361495e | ||
|
|
50434201cf | ||
|
|
f7b5dbd12f | ||
|
|
71e69d34ed | ||
|
|
738684c4c7 | ||
|
|
bcf892ca37 | ||
|
|
92b0c7f0b7 | ||
|
|
f3e09c3a4b | ||
|
|
fa2d0578c0 | ||
|
|
da96344690 | ||
|
|
a8d6e5b1ea | ||
|
|
5691554442 | ||
|
|
a01065908d | ||
|
|
935e882f3e | ||
|
|
cb9b4c07e5 |
249
.github/workflows/main-docker.yml
vendored
Normal file
@@ -0,0 +1,249 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "develop"
|
||||
- "feature/update**"
|
||||
- "feature/server_esm**"
|
||||
paths-ignore:
|
||||
- "docs/**"
|
||||
- "bin/**"
|
||||
tags:
|
||||
- "v*"
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
GHCR_REGISTRY: ghcr.io
|
||||
DOCKERHUB_REGISTRY: docker.io
|
||||
IMAGE_NAME: ${{ github.repository_owner }}/notes
|
||||
TEST_TAG: ${{ github.repository_owner }}/notes:test
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
test_docker:
|
||||
name: Check Docker build
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- dockerfile: Dockerfile.alpine
|
||||
- dockerfile: Dockerfile
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set IMAGE_NAME to lowercase
|
||||
run: echo "IMAGE_NAME=${IMAGE_NAME,,}" >> $GITHUB_ENV
|
||||
- name: Set TEST_TAG to lowercase
|
||||
run: echo "TEST_TAG=${TEST_TAG,,}" >> $GITHUB_ENV
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "npm"
|
||||
|
||||
- run: npm ci
|
||||
|
||||
- name: Run the TypeScript build
|
||||
run: npx tsc
|
||||
|
||||
- name: Create server-package.json
|
||||
run: cat package.json | grep -v electron > server-package.json
|
||||
|
||||
- name: Build and export to Docker
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ${{ matrix.dockerfile }}
|
||||
load: true
|
||||
tags: ${{ env.TEST_TAG }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Validate container run output
|
||||
run: |
|
||||
CONTAINER_ID=$(docker run -d --log-driver=journald --rm --name trilium_local ${{ env.TEST_TAG }})
|
||||
echo "Container ID: $CONTAINER_ID"
|
||||
|
||||
- name: Wait for the healthchecks to pass
|
||||
uses: stringbean/docker-healthcheck-action@v1
|
||||
with:
|
||||
container: trilium_local
|
||||
wait-time: 50
|
||||
require-status: running
|
||||
require-healthy: true
|
||||
|
||||
# Print the entire log of the container thus far, regardless if the healthcheck failed or succeeded
|
||||
- name: Print entire log
|
||||
if: always()
|
||||
run: |
|
||||
journalctl -u docker CONTAINER_NAME=trilium_local --no-pager
|
||||
|
||||
build:
|
||||
name: Build Docker images
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- test_docker
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
attestations: write
|
||||
id-token: write
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- dockerfile: Dockerfile.alpine
|
||||
platform: linux/amd64
|
||||
- dockerfile: Dockerfile
|
||||
platform: linux/arm64
|
||||
- dockerfile: Dockerfile
|
||||
platform: linux/arm/v7
|
||||
steps:
|
||||
- name: Prepare
|
||||
run: |
|
||||
platform=${{ matrix.platform }}
|
||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||
- name: Set IMAGE_NAME to lowercase
|
||||
run: echo "IMAGE_NAME=${IMAGE_NAME,,}" >> $GITHUB_ENV
|
||||
- name: Set TEST_TAG to lowercase
|
||||
run: echo "TEST_TAG=${TEST_TAG,,}" >> $GITHUB_ENV
|
||||
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=tag
|
||||
type=sha
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "npm"
|
||||
- run: npm ci
|
||||
- name: Run the TypeScript build
|
||||
run: npx tsc
|
||||
- name: Create server-package.json
|
||||
run: cat package.json | grep -v electron > server-package.json
|
||||
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ${{ env.GHCR_REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ${{ env.DOCKERHUB_REGISTRY }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Build and push by digest
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ${{ matrix.dockerfile }}
|
||||
platforms: ${{ matrix.platform }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
outputs: type=image,name=${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
- name: Export digest
|
||||
run: |
|
||||
mkdir -p /tmp/digests
|
||||
digest="${{ steps.build.outputs.digest }}"
|
||||
touch "/tmp/digests/${digest#sha256:}"
|
||||
|
||||
- name: Upload digest
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: digests-${{ env.PLATFORM_PAIR }}
|
||||
path: /tmp/digests/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
merge:
|
||||
name: Merge manifest lists
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build
|
||||
steps:
|
||||
- name: Download digests
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: /tmp/digests
|
||||
pattern: digests-*
|
||||
merge-multiple: true
|
||||
- name: Set IMAGE_NAME to lowercase
|
||||
run: echo "IMAGE_NAME=${IMAGE_NAME,,}" >> $GITHUB_ENV
|
||||
- name: Set TEST_TAG to lowercase
|
||||
run: echo "TEST_TAG=${TEST_TAG,,}" >> $GITHUB_ENV
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ${{ env.GHCR_REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ${{ env.DOCKERHUB_REGISTRY }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Create manifest list and push
|
||||
working-directory: /tmp/digests
|
||||
run: |
|
||||
# Extract the branch or tag name from the ref
|
||||
REF_NAME=$(echo "${GITHUB_REF}" | sed 's/refs\/heads\///' | sed 's/refs\/tags\///')
|
||||
|
||||
# Create and push the manifest list with both the branch/tag name and the commit SHA
|
||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
||||
-t ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:${REF_NAME} \
|
||||
$(printf '${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
|
||||
|
||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
||||
-t ${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${REF_NAME} \
|
||||
$(printf '${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
|
||||
|
||||
- name: Inspect image
|
||||
run: |
|
||||
docker buildx imagetools inspect ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
|
||||
docker buildx imagetools inspect ${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
|
||||
246
.github/workflows/main.yml
vendored
@@ -2,84 +2,76 @@ name: Main
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "develop"
|
||||
- "feature/update**"
|
||||
- "feature/server_esm**"
|
||||
paths-ignore:
|
||||
- "docs/**"
|
||||
- "bin/**"
|
||||
tags:
|
||||
- "v*"
|
||||
- ".github/workflows/main-docker.yml"
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
GHCR_REGISTRY: ghcr.io
|
||||
DOCKERHUB_REGISTRY: docker.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
build_darwin-x64:
|
||||
name: Build macOS x86_64
|
||||
runs-on: ubuntu-latest
|
||||
make-electron:
|
||||
name: Make Electron
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [x64, arm64]
|
||||
os:
|
||||
- name: macos
|
||||
image: macos-latest
|
||||
extension: dmg
|
||||
- name: linux
|
||||
image: ubuntu-latest
|
||||
extension: deb
|
||||
- name: windows
|
||||
image: windows-latest
|
||||
extension: exe
|
||||
runs-on: ${{ matrix.os.image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "npm"
|
||||
- run: npm ci
|
||||
- run: |
|
||||
npm run update-build-info
|
||||
./bin/build-mac-x64.sh
|
||||
- uses: actions/upload-artifact@v4
|
||||
- name: Set up Python for appdmg to be installed
|
||||
if: ${{ matrix.os.name == 'macos' }}
|
||||
run: brew install python-setuptools
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Update build info
|
||||
run: npm run update-build-info
|
||||
- name: Run electron-forge
|
||||
run: npm run make-electron -- --arch=${{ matrix.arch }}
|
||||
- name: Prepare artifacts (Unix)
|
||||
if: runner.os != 'windows'
|
||||
run: |
|
||||
mkdir -p upload
|
||||
file=$(find out/make -name '*.zip' -print -quit)
|
||||
cp "$file" "upload/TriliumNextNotes-${{ matrix.os.name }}-${{ matrix.arch }}-${{ github.ref_name }}.zip"
|
||||
file=$(find out/make -name '*.${{ matrix.os.extension }}' -print -quit)
|
||||
cp "$file" "upload/TriliumNextNotes-${{ matrix.os.name }}-${{ matrix.arch }}-${{ github.ref_name }}.${{ matrix.os.extension }}"
|
||||
- name: Prepare artifacts (Windows)
|
||||
if: runner.os == 'windows'
|
||||
run: |
|
||||
mkdir upload
|
||||
$file = Get-ChildItem -Path out/make -Filter '*.zip' -Recurse | Select-Object -First 1
|
||||
Copy-Item -Path $file.FullName -Destination "upload/TriliumNextNotes-${{ matrix.os.name }}-${{ matrix.arch }}-${{ github.ref_name }}.zip"
|
||||
$file = Get-ChildItem -Path out/make -Filter '*.${{ matrix.os.extension }}' -Recurse | Select-Object -First 1
|
||||
Copy-Item -Path $file.FullName -Destination "upload/TriliumNextNotes-${{ matrix.os.name }}-${{ matrix.arch }}-${{ github.ref_name }}.${{ matrix.os.extension }}"
|
||||
- name: Publish artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: trilium-mac-x64.zip
|
||||
path: dist/trilium-mac-x64*.zip
|
||||
build_darwin-arm64:
|
||||
name: Build macOS aarch64
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v4
|
||||
name: TriliumNextNotes ${{ matrix.os.name }} ${{ matrix.arch }}.zip
|
||||
path: upload/*.zip
|
||||
- name: Publish installer artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "npm"
|
||||
- run: npm ci
|
||||
- run: |
|
||||
npm run update-build-info
|
||||
./bin/build-mac-arm64.sh
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: trilium-mac-arm64.zip
|
||||
path: dist/trilium-mac-arm64*.zip
|
||||
build_linux-x64:
|
||||
name: Build Linux x86_64
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "npm"
|
||||
- run: npm ci
|
||||
- run: |
|
||||
npm run update-build-info
|
||||
./bin/build-linux-x64.sh
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: trilium-linux-x64.tar.xz
|
||||
path: dist/trilium-linux-x64-*.tar.xz
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: trilium_amd64.deb
|
||||
path: dist/trilium_*.deb
|
||||
name: TriliumNextNotes ${{ matrix.os.name }} ${{ matrix.arch }}.${{matrix.os.extension}}
|
||||
path: upload/*.${{ matrix.os.extension }}
|
||||
build_linux_server-x64:
|
||||
name: Build Linux Server x86_64
|
||||
runs-on: ubuntu-latest
|
||||
@@ -90,131 +82,19 @@ jobs:
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "npm"
|
||||
- run: npm ci
|
||||
- run: |
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Run Linux server build (x86_64)
|
||||
run: |
|
||||
npm run update-build-info
|
||||
./bin/build-server.sh
|
||||
- name: Prepare artifacts
|
||||
if: runner.os != 'windows'
|
||||
run: |
|
||||
mkdir -p upload
|
||||
file=$(find dist -name '*.tar.xz' -print -quit)
|
||||
cp "$file" "upload/TriliumNextNotes-linux-x64-${{ github.ref_name }}.tar.xz"
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: trilium-linux-x64-server.tar.xz
|
||||
path: dist/trilium-linux-x64-server-*.tar.xz
|
||||
build_windows-x64:
|
||||
name: Build Windows x86_64
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Wine
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
wget -qO - https://dl.winehq.org/wine-builds/winehq.key | sudo apt-key add -
|
||||
sudo add-apt-repository ppa:cybermax-dexter/sdl2-backport
|
||||
sudo apt-add-repository "deb https://dl.winehq.org/wine-builds/ubuntu $(lsb_release -cs) main"
|
||||
sudo apt install --install-recommends winehq-stable
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "npm"
|
||||
- run: npm ci
|
||||
- run: |
|
||||
npm run update-build-info
|
||||
./bin/build-win-x64.sh DONTPACK
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: trilium-windows-x64
|
||||
path: dist/trilium-windows-x64
|
||||
build_windows-installer:
|
||||
name: Build Windows x86_64 (Setup)
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "npm"
|
||||
- run: npm ci
|
||||
- name: Run installer build
|
||||
run: |
|
||||
npm run update-build-info
|
||||
npm run make-electron
|
||||
- name: Publish installer artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: TriliumNext Notes for Windows (Setup)
|
||||
path: out/make/squirrel.windows/x64/*.exe
|
||||
build_docker:
|
||||
name: Build Docker images
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
attestations: write
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Extract metadata (tags, labels) for GHCR image
|
||||
id: ghcr-meta
|
||||
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
|
||||
with:
|
||||
images: ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
- name: Extract metadata (tags, labels) for DockerHub image
|
||||
id: dh-meta
|
||||
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
|
||||
with:
|
||||
images: ${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "npm"
|
||||
- run: npm ci
|
||||
- name: Run the TypeScript build
|
||||
run: npx tsc
|
||||
- name: Create server-package.json
|
||||
run: cat package.json | grep -v electron > server-package.json
|
||||
- name: Log in to the GHCR container registry
|
||||
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
|
||||
with:
|
||||
registry: ${{ env.GHCR_REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
- name: Build and push container image to GHCR
|
||||
uses: docker/build-push-action@v6
|
||||
id: ghcr-push
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ${{ steps.ghcr-meta.outputs.tags }}
|
||||
labels: ${{ steps.ghcr-meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
- name: Generate and push artifact attestation to GHCR
|
||||
uses: actions/attest-build-provenance@v1
|
||||
with:
|
||||
subject-name: ${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME}}
|
||||
subject-digest: ${{ steps.ghcr-push.outputs.digest }}
|
||||
push-to-registry: true
|
||||
- name: Log in to the DockerHub container registry
|
||||
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
|
||||
with:
|
||||
registry: ${{ env.DOCKERHUB_REGISTRY }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push image to DockerHub
|
||||
uses: docker/build-push-action@v6
|
||||
id: dh-push
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ${{ steps.dh-meta.outputs.tags }}
|
||||
labels: ${{ steps.dh-meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
- name: Generate and push artifact attestation to DockerHub
|
||||
uses: actions/attest-build-provenance@v1
|
||||
with:
|
||||
subject-name: ${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME}}
|
||||
subject-digest: ${{ steps.dh-push.outputs.digest }}
|
||||
push-to-registry: true
|
||||
name: TriliumNextNotes linux server x64
|
||||
path: upload/TriliumNextNotes-linux-x64-${{ github.ref_name }}.tar.xz
|
||||
|
||||
122
.github/workflows/nightly.yml
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
name: Nightly Release
|
||||
on:
|
||||
# This can be used to automatically publish nightlies at UTC nighttime
|
||||
schedule:
|
||||
- cron: '0 2 * * *' # run at 2 AM UTC
|
||||
# This can be used to allow manually triggering nightlies from the web interface
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
nightly-electron:
|
||||
name: Deploy nightly
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [x64, arm64]
|
||||
os:
|
||||
- name: macos
|
||||
image: macos-latest
|
||||
extension: dmg
|
||||
- name: linux
|
||||
image: ubuntu-latest
|
||||
extension: deb
|
||||
- name: windows
|
||||
image: windows-latest
|
||||
extension: exe
|
||||
runs-on: ${{ matrix.os.image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
- name: Set up Python for appdmg to be installed
|
||||
if: ${{ matrix.os.name == 'macos' }}
|
||||
run: brew install python-setuptools
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Update build info
|
||||
run: npm run update-build-info
|
||||
- name: Run electron-forge
|
||||
run: npm run make-electron -- --arch=${{ matrix.arch }}
|
||||
- name: Prepare artifacts (Unix)
|
||||
if: runner.os != 'windows'
|
||||
run: |
|
||||
mkdir -p upload
|
||||
file=$(find out/make -name '*.zip' -print -quit)
|
||||
cp "$file" "upload/TriliumNextNotes-${{ matrix.os.name }}-${{ matrix.arch }}.zip"
|
||||
file=$(find out/make -name '*.${{ matrix.os.extension }}' -print -quit)
|
||||
cp "$file" "upload/TriliumNextNotes-${{ matrix.os.name }}-${{ matrix.arch }}.${{ matrix.os.extension }}"
|
||||
- name: Prepare artifacts (Windows)
|
||||
if: runner.os == 'windows'
|
||||
run: |
|
||||
mkdir upload
|
||||
$file = Get-ChildItem -Path out/make -Filter '*.zip' -Recurse | Select-Object -First 1
|
||||
Copy-Item -Path $file.FullName -Destination "upload/TriliumNextNotes-${{ matrix.os.name }}-${{ matrix.arch }}.zip"
|
||||
$file = Get-ChildItem -Path out/make -Filter '*.${{ matrix.os.extension }}' -Recurse | Select-Object -First 1
|
||||
Copy-Item -Path $file.FullName -Destination "upload/TriliumNextNotes-${{ matrix.os.name }}-${{ matrix.arch }}.${{ matrix.os.extension }}"
|
||||
- name: Publish artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: TriliumNextNotes ${{ matrix.os.name }} ${{ matrix.arch }}
|
||||
path: upload/*.zip
|
||||
overwrite: true
|
||||
- name: Publish installer artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: TriliumNextNotes ${{ matrix.os.name }} ${{ matrix.arch }}
|
||||
path: upload/*.${{ matrix.os.extension }}
|
||||
overwrite: true
|
||||
|
||||
- name: Deploy release
|
||||
uses: WebFreak001/deploy-nightly@v3.1.0
|
||||
with:
|
||||
# upload_url: # find out this value by opening https://api.github.com/repos/<owner>/<repo>/releases in your browser and copy the full "upload_url" value including the {?name,label} part
|
||||
# release_id: # same as above (id can just be taken out the upload_url, it's used to find old releases)
|
||||
asset_path: upload/TriliumNextNotes-${{ matrix.os.name }}-${{ matrix.arch }}.zip # path to archive to upload
|
||||
asset_name: TriliumNextNotes-${{ matrix.os.name }}-${{ matrix.arch }}-nightly.zip # name to upload the release as, use $$ to insert date (YYYYMMDD) and 6 letter commit hash
|
||||
asset_content_type: application/zip # required by GitHub API
|
||||
- name: Deploy installer release
|
||||
uses: WebFreak001/deploy-nightly@v3.1.0
|
||||
with:
|
||||
# upload_url: # find out this value by opening https://api.github.com/repos/<owner>/<repo>/releases in your browser and copy the full "upload_url" value including the {?name,label} part
|
||||
# release_id: # same as above (id can just be taken out the upload_url, it's used to find old releases)
|
||||
asset_path: upload/TriliumNextNotes-${{ matrix.os.name }}-${{ matrix.arch }}.${{ matrix.os.extension }} # path to archive to upload
|
||||
asset_name: TriliumNextNotes-${{ matrix.os.name }}-${{ matrix.arch }}-nightly.${{ matrix.os.extension }} # name to upload the release as, use $$ to insert date (YYYYMMDD) and 6 letter commit hash
|
||||
asset_content_type: application/zip # required by GitHub API
|
||||
nightly-server:
|
||||
name: Deploy server nightly
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "npm"
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Run Linux server build (x86_64)
|
||||
run: |
|
||||
npm run update-build-info
|
||||
./bin/build-server.sh
|
||||
- name: Prepare artifacts
|
||||
if: runner.os != 'windows'
|
||||
run: |
|
||||
mkdir -p upload
|
||||
file=$(find dist -name '*.tar.xz' -print -quit)
|
||||
cp "$file" "upload/TriliumNextNotes-linux-x64-${{ github.ref_name }}.tar.xz"
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: TriliumNextNotes linux server x64
|
||||
path: upload/TriliumNextNotes-linux-x64-${{ github.ref_name }}.tar.xz
|
||||
overwrite: true
|
||||
|
||||
- name: Deploy release
|
||||
uses: WebFreak001/deploy-nightly@v3.1.0
|
||||
with:
|
||||
# upload_url: # find out this value by opening https://api.github.com/repos/<owner>/<repo>/releases in your browser and copy the full "upload_url" value including the {?name,label} part
|
||||
# release_id: # same as above (id can just be taken out the upload_url, it's used to find old releases)
|
||||
asset_path: upload/TriliumNextNotes-linux-x64-${{ github.ref_name }}.tar.xz # path to archive to upload
|
||||
asset_name: TriliumNextNotes-linux-x64-nightly.zip # name to upload the release as, use $$ to insert date (YYYYMMDD) and 6 letter commit hash
|
||||
asset_content_type: application/zip # required by GitHub API
|
||||
27
.github/workflows/playwright.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
name: Playwright Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ main, master ]
|
||||
pull_request:
|
||||
branches: [ main, master ]
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Install Playwright Browsers
|
||||
run: npx playwright install --with-deps
|
||||
- name: Run Playwright tests
|
||||
run: npx playwright test
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-report
|
||||
path: playwright-report/
|
||||
retention-days: 30
|
||||
95
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
name: Release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
workflow_dispatch:
|
||||
permissions:
|
||||
contents: write
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
make-electron:
|
||||
name: Make Electron
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [x64, arm64]
|
||||
os:
|
||||
- name: macos
|
||||
image: macos-latest
|
||||
extension: dmg
|
||||
- name: linux
|
||||
image: ubuntu-latest
|
||||
extension: deb
|
||||
- name: windows
|
||||
image: windows-latest
|
||||
extension: exe
|
||||
runs-on: ${{ matrix.os.image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
- name: Set up Python for appdmg to be installed
|
||||
if: ${{ matrix.os.name == 'macos' }}
|
||||
run: brew install python-setuptools
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Update build info
|
||||
run: npm run update-build-info
|
||||
- name: Run electron-forge
|
||||
run: npm run make-electron -- --arch=${{ matrix.arch }}
|
||||
- name: Prepare artifacts (Unix)
|
||||
if: runner.os != 'windows'
|
||||
run: |
|
||||
mkdir -p upload
|
||||
file=$(find out/make -name '*.zip' -print -quit)
|
||||
cp "$file" "upload/TriliumNextNotes-${{ github.ref_name }}-${{ matrix.os.name }}-${{ matrix.arch }}.zip"
|
||||
file=$(find out/make -name '*.${{ matrix.os.extension }}' -print -quit)
|
||||
cp "$file" "upload/TriliumNextNotes-${{ github.ref_name }}-${{ matrix.os.name }}-${{ matrix.arch }}.${{ matrix.os.extension }}"
|
||||
- name: Prepare artifacts (Windows)
|
||||
if: runner.os == 'windows'
|
||||
run: |
|
||||
mkdir upload
|
||||
$file = Get-ChildItem -Path out/make -Filter '*.zip' -Recurse | Select-Object -First 1
|
||||
Copy-Item -Path $file.FullName -Destination "upload/TriliumNextNotes-${{ github.ref_name }}-${{ matrix.os.name }}-${{ matrix.arch }}.zip"
|
||||
$file = Get-ChildItem -Path out/make -Filter '*.${{ matrix.os.extension }}' -Recurse | Select-Object -First 1
|
||||
Copy-Item -Path $file.FullName -Destination "upload/TriliumNextNotes-${{ github.ref_name }}-${{ matrix.os.name }}-${{ matrix.arch }}.${{ matrix.os.extension }}"
|
||||
- name: Publish release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
draft: true
|
||||
fail_on_unmatched_files: true
|
||||
files: upload/*.*
|
||||
build_linux_server-x64:
|
||||
name: Build Linux Server x86_64
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "npm"
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Run Linux server build (x86_64)
|
||||
run: |
|
||||
npm run update-build-info
|
||||
./bin/build-server.sh
|
||||
- name: Prepare artifacts
|
||||
if: runner.os != 'windows'
|
||||
run: |
|
||||
mkdir -p upload
|
||||
file=$(find dist -name '*.tar.xz' -print -quit)
|
||||
cp "$file" "upload/TriliumNextNotes-${{ github.ref_name }}-server-linux-x64.tar.xz"
|
||||
- name: Publish release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
draft: true
|
||||
fail_on_unmatched_files: true
|
||||
files: upload/*.*
|
||||
19
.gitignore
vendored
@@ -5,12 +5,20 @@ build/
|
||||
src/public/app-dist/
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
*.db
|
||||
!integration-tests/db/document.db
|
||||
integration-tests/db/log
|
||||
integration-tests/db/sessions
|
||||
integration-tests/db/backup
|
||||
integration-tests/db/session_secret.txt
|
||||
|
||||
config.ini
|
||||
cert.key
|
||||
cert.crt
|
||||
server-package.json
|
||||
.idea/httpRequests/
|
||||
.idea/shelf/
|
||||
data/
|
||||
data-test/
|
||||
tmp/
|
||||
@@ -18,8 +26,9 @@ tmp/
|
||||
|
||||
out/
|
||||
|
||||
images/app-icons/png/16x16.png
|
||||
images/app-icons/png/32x32.png
|
||||
images/app-icons/png/512x512.png
|
||||
images/app-icons/png/1024x1024.png
|
||||
images/app-icons/mac/*.png
|
||||
images/app-icons/mac/*.png
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/blob-report/
|
||||
/playwright/.cache/
|
||||
/playwright/.auth/
|
||||
8
.idea/codeStyles/Project.xml
generated
@@ -6,8 +6,10 @@
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</value>
|
||||
</option>
|
||||
<JSCodeStyleSettings version="0">
|
||||
<option name="USE_EXPLICIT_JS_EXTENSION" value="TRUE" />
|
||||
</JSCodeStyleSettings>
|
||||
<codeStyleSettings language="JSON">
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
3
.vscode/i18n-ally-custom-framework.yml
vendored
@@ -3,6 +3,7 @@
|
||||
languageIds:
|
||||
- javascript
|
||||
- typescript
|
||||
- html
|
||||
|
||||
# An array of RegExes to find the key usage. **The key should be captured in the first match group**.
|
||||
# You should unescape RegEx strings in order to fit in the YAML file
|
||||
@@ -24,6 +25,8 @@ scopeRangeRegex: "useTranslation\\(\\s*\\[?\\s*['\"`](.*?)['\"`]"
|
||||
# The "$1" will be replaced by the keypath specified.
|
||||
refactorTemplates:
|
||||
- t("$1")
|
||||
- ${t("$1")}
|
||||
- <%= t("$1") %>
|
||||
|
||||
|
||||
# If set to true, only enables this custom framework (will disable all built-in frameworks)
|
||||
|
||||
7
.vscode/i18n-ally-reviews.yml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
# Review comments generated by i18n-ally. Please commit this file.
|
||||
|
||||
reviews:
|
||||
help.inPageSearch:
|
||||
description: >-
|
||||
Describes the shortcut which triggers a search within the current
|
||||
page/note only
|
||||
9
.vscode/settings.json
vendored
@@ -6,9 +6,16 @@
|
||||
"i18n-ally.sourceLanguage": "en",
|
||||
"i18n-ally.keystyle": "nested",
|
||||
"i18n-ally.localesPaths": [
|
||||
"./src/public/translations"
|
||||
"./src/public/translations",
|
||||
"./translations"
|
||||
],
|
||||
"[jsonc]": {
|
||||
"editor.defaultFormatter": "vscode.json-language-features"
|
||||
},
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||
},
|
||||
}
|
||||
|
||||
52
Dockerfile
@@ -1,8 +1,8 @@
|
||||
# !!! Don't try to build this Dockerfile directly, run it through bin/build-docker.sh script !!!
|
||||
FROM node:20.15.1-alpine
|
||||
FROM node:20.15.1-bullseye-slim
|
||||
|
||||
# Configure system dependencies
|
||||
RUN apk add --no-cache --virtual .build-dependencies \
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
autoconf \
|
||||
automake \
|
||||
g++ \
|
||||
@@ -11,40 +11,50 @@ RUN apk add --no-cache --virtual .build-dependencies \
|
||||
make \
|
||||
nasm \
|
||||
libpng-dev \
|
||||
python3
|
||||
python3 \
|
||||
gosu \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Create app directory
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Bundle app source
|
||||
COPY . .
|
||||
|
||||
COPY server-package.json package.json
|
||||
|
||||
# Copy TypeScript build artifacts into the original directory structure.
|
||||
RUN ls
|
||||
RUN cp -R build/src/* src/.
|
||||
RUN rm -r build
|
||||
# Copy the healthcheck
|
||||
RUN cp -R build/src/* src/. && \
|
||||
cp build/docker_healthcheck.js . && \
|
||||
rm -r build && \
|
||||
rm docker_healthcheck.ts
|
||||
|
||||
# Install app dependencies
|
||||
RUN set -x \
|
||||
&& npm install \
|
||||
&& apk del .build-dependencies \
|
||||
&& npm run webpack \
|
||||
&& npm prune --omit=dev \
|
||||
&& cp src/public/app/share.js src/public/app-dist/. \
|
||||
&& cp -r src/public/app/doc_notes src/public/app-dist/. \
|
||||
&& rm -rf src/public/app \
|
||||
&& rm src/services/asset_path.ts
|
||||
RUN apt-get purge -y --auto-remove \
|
||||
autoconf \
|
||||
automake \
|
||||
g++ \
|
||||
gcc \
|
||||
libtool \
|
||||
make \
|
||||
nasm \
|
||||
libpng-dev \
|
||||
python3 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
RUN npm install && \
|
||||
npm run webpack && \
|
||||
npm prune --omit=dev
|
||||
RUN cp src/public/app/share.js src/public/app-dist/. && \
|
||||
cp -r src/public/app/doc_notes src/public/app-dist/. && \
|
||||
rm -rf src/public/app && rm src/services/asset_path.ts
|
||||
|
||||
# Some setup tools need to be kept
|
||||
RUN apk add --no-cache su-exec shadow
|
||||
|
||||
# Add application user and setup proper volume permissions
|
||||
RUN adduser -s /bin/false node; exit 0
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
gosu \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Start the application
|
||||
EXPOSE 8080
|
||||
CMD [ "./start-docker.sh" ]
|
||||
|
||||
HEALTHCHECK --start-period=10s CMD exec su-exec node node docker_healthcheck.js
|
||||
HEALTHCHECK --start-period=10s CMD exec gosu node node docker_healthcheck.js
|
||||
53
Dockerfile.alpine
Normal file
@@ -0,0 +1,53 @@
|
||||
# !!! Don't try to build this Dockerfile directly, run it through bin/build-docker.sh script !!!
|
||||
FROM node:20.15.1-alpine
|
||||
|
||||
# Configure system dependencies
|
||||
RUN apk add --no-cache --virtual .build-dependencies \
|
||||
autoconf \
|
||||
automake \
|
||||
g++ \
|
||||
gcc \
|
||||
libtool \
|
||||
make \
|
||||
nasm \
|
||||
libpng-dev \
|
||||
python3
|
||||
|
||||
# Create app directory
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Bundle app source
|
||||
COPY . .
|
||||
|
||||
COPY server-package.json package.json
|
||||
|
||||
# Copy TypeScript build artifacts into the original directory structure.
|
||||
# Copy the healthcheck
|
||||
RUN cp -R build/src/* src/. && \
|
||||
cp build/docker_healthcheck.js . && \
|
||||
rm -r build && \
|
||||
rm docker_healthcheck.ts
|
||||
|
||||
# Install app dependencies
|
||||
RUN set -x && \
|
||||
npm install && \
|
||||
apk del .build-dependencies && \
|
||||
npm run webpack && \
|
||||
npm prune --omit=dev && \
|
||||
cp src/public/app/share.js src/public/app-dist/. && \
|
||||
cp -r src/public/app/doc_notes src/public/app-dist/. && \
|
||||
rm -rf src/public/app && \
|
||||
rm src/services/asset_path.ts
|
||||
|
||||
|
||||
# Some setup tools need to be kept
|
||||
RUN apk add --no-cache su-exec shadow
|
||||
|
||||
# Add application user and setup proper volume permissions
|
||||
RUN adduser -s /bin/false node; exit 0
|
||||
|
||||
# Start the application
|
||||
EXPOSE 8080
|
||||
CMD [ "./start-docker.sh" ]
|
||||
|
||||
HEALTHCHECK --start-period=10s CMD exec su-exec node node docker_healthcheck.js
|
||||
@@ -1,6 +1,6 @@
|
||||
# TriliumNext Notes
|
||||
|
||||
[English](https://github.com/TriliumNext/Notes/blob/master/README.md) | [Chinese](https://github.com/TriliumNext/Notes/blob/master/README-ZH_CN.md) | [Russian](https://github.com/TriliumNext/Notes/blob/master/README.ru.md) | [Japanese](https://github.com/TriliumNext/Notes/blob/master/README.ja.md) | [Italian](https://github.com/TriliumNext/Notes/blob/master/README.it.md)
|
||||
[English](./README.md) | [Chinese](./README-ZH_CN.md) | [Russian](./README.ru.md) | [Japanese](./README.ja.md) | [Italian](./README.it.md) | [Spanish](./README.es.md)
|
||||
|
||||
TriliumNext Notes 是一个层次化的笔记应用程序,专注于建立大型个人知识库。请参阅[屏幕截图](https://triliumnext.github.io/Docs/Wiki/screenshot-tour)以快速了解:
|
||||
|
||||
@@ -76,7 +76,7 @@ Trilium 也提供 Flatpak:
|
||||
|
||||
或者克隆本仓库到本地,并运行
|
||||
|
||||
```
|
||||
```shell
|
||||
npm install
|
||||
npm run start-server
|
||||
```
|
||||
|
||||
106
README.es.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# TriliumNext Notes
|
||||
|
||||
[English](./README.md) | [Chinese](./README-ZH_CN.md) | [Russian](./README.ru.md) | [Japanese](./README.ja.md) | [Italian](./README.it.md) | [Spanish](./README.es.md)
|
||||
|
||||
TriliumNext Notes es una aplicación de toma de notas jerárquicas multi-plataforma y de código libre con un enfoque en la construcción de grandes bases de conocimiento personal.
|
||||
|
||||
Vea estas [capturas de pantalla](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) para un vistazo rápido:
|
||||
|
||||
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="https://github.com/TriliumNext/Docs/blob/main/Wiki/images/screenshot.png?raw=true" alt="Trilium Screenshot" width="1000"></a>
|
||||
|
||||
## ⚠️ ¿Por qué usar TriliumNext?
|
||||
|
||||
[El proyecto Trilium original está en modo de mantenimiento](https://github.com/zadam/trilium/issues/4620)
|
||||
|
||||
### ¿Cómo migrar desde Trilium?
|
||||
|
||||
No hay pasos de migración especiales para migrar de una instancia de zadam/Trilium a una instancia de TriliumNext/Notes. Simplemente actualice su instancia de Trilium a la última versión e [instale TriliumNext/Notes como de costumbre](#-Instalación)
|
||||
|
||||
## 💬 Discuta con nosotros
|
||||
|
||||
Siéntase libre de unirse a nuestras conversaciones oficiales. ¡Nos encantaría escuchar de las características, sugerencias o problemas que pueda tener!
|
||||
|
||||
- [Matrix](https://matrix.to/#/#triliumnext:matrix.org) (Para discusiones síncronas)
|
||||
- La sala `General` es replicada a [XMPP](xmpp:discuss@trilium.thisgreat.party?join)
|
||||
- [Discusiones de GitHub](https://github.com/TriliumNext/Notes/discussions) (Para discusiones asíncronas)
|
||||
- [Wiki](https://triliumnext.github.io/Docs/) (Para preguntas frecuentes y guías de usuario)
|
||||
|
||||
## 🎁 Características
|
||||
|
||||
- Las notas pueden ser acomodadas en un árbol de profundidad arbitraria. Una sola nota puede ser colocada en múltiples lugares del árbol (vea [clonar](https://triliumnext.github.io/Docs/Wiki/cloning-notes)
|
||||
- Edición de notas WYSIWYG enriquecida que incluye, por ejemplo, tablas, imágenes y [matemáticas](https://triliumnext.github.io/Docs/Wiki/text-notes) con [autoformato](https://triliumnext.github.io/Docs/Wiki/text-notes#autoformat) markdown
|
||||
- Soporte para editar [notas con código fuente](https://triliumnext.github.io/Docs/Wiki/code-notes), incluyendo resaltado de sintaxis
|
||||
- Rápida y sencilla [navegación entre notas](https://triliumnext.github.io/Docs/Wiki/note-navigation), búsqueda de texto completo y [elevación de notas](https://triliumnext.github.io/Docs/Wiki/note-hoisting)
|
||||
- [Versionado de notas](https://triliumnext.github.io/Docs/Wiki/note-revisions) sutil
|
||||
- Los [atributos](https://triliumnext.github.io/Docs/Wiki/attributes) de las notas pueden utilizarse para organización, realizar consultas y [scripts](https://triliumnext.github.io/Docs/Wiki/scripts) avanzados
|
||||
- [Sincronización](https://triliumnext.github.io/Docs/Wiki/synchronization) con servidor de sincronización propio
|
||||
- existe un [servicio de terceros para alojar el servidor de sincronización](https://trilium.cc/paid-hosting)
|
||||
- [Compartir](https://triliumnext.github.io/Docs/Wiki/sharing) (publicar) notas al Internet público
|
||||
- Fuerte [encriptación de notas](https://triliumnext.github.io/Docs/Wiki/protected-notes) con granularidad para cada nota
|
||||
- Esbozo de diagramas con Excalidraw incorporado (tipo de nota «canvas»)
|
||||
- [Mapas de relaciones](<https://triliumnext.github.io/Docs/Wiki/relation-map>) y [mapas de enlaces](https://triliumnext.github.io/Docs/Wiki/link-map) para visualizar las notas y sus relaciones
|
||||
- [Scripting](https://triliumnext.github.io/Docs/Wiki/scripts) - vea [casos de uso avanzados](https://triliumnext.github.io/Docs/Wiki/advanced-showcases)
|
||||
- [REST API](https://triliumnext.github.io/Docs/Wiki/etapi) para automatización
|
||||
- Escala bien tanto en uso como en rendimiento a partir de 100,000 notas
|
||||
- [Interfaz móvil](https://triliumnext.github.io/Docs/Wiki/mobile-frontend) optimizada para teléfonos inteligentes y tabletas
|
||||
- [Tema nocturno](https://triliumnext.github.io/Docs/Wiki/themes)
|
||||
- Importación y exportación de [Evernote](https://triliumnext.github.io/Docs/Wiki/evernote-import) y [Markdown](https://triliumnext.github.io/Docs/Wiki/markdown)
|
||||
- [Web Clipper](https://triliumnext.github.io/Docs/Wiki/web-clipper) para guardar fácilmente contenido web
|
||||
|
||||
✨ Consulte los/las siguientes recursos/comunidades de terceros para obtener más información sobre complementos para TriliumNext:
|
||||
|
||||
- [awesome-trilium](https://github.com/Nriver/awesome-trilium) para temas, scripts, plugins y más de terceros.
|
||||
- [TriliumRocks!](https://trilium.rocks/) para tutoriales, guías y mucho más.
|
||||
|
||||
## 🏗 Instalación
|
||||
|
||||
### Escritorio
|
||||
|
||||
Para usar TriliumNext en su máquina de escritorio (Linux, MacOS y Windows) tiene algunas opciones:
|
||||
|
||||
- Descargue la versión binaria para su plataforma desde la [página de lanzamientos](https://github.com/TriliumNext/Notes/releases/latest), descomprima el paquete y ejecute el ejecutable `trilium`.
|
||||
- Acceda a TriliumNext a través de la interfaz web de una instalación de servidor (ver más abajo)
|
||||
- Actualmente solo las últimas versiones de Chrome y Firefox son compatibles (y están probadas).
|
||||
- (Próximamente) TriliumNext también se proporcionará como un Flatpak
|
||||
|
||||
### Móvil
|
||||
|
||||
Para usar TriliumNext en un dispositivo móvil:
|
||||
|
||||
- Utilice un navegador web móvil para acceder a la interfaz móvil de una instalación de servidor (ver más abajo)
|
||||
- El uso de una aplicación móvil aún no está soportado ([vea aquí](https://github.com/TriliumNext/Notes/issues/72)) para seguir las mejoras móviles.
|
||||
|
||||
### Servidor
|
||||
|
||||
Para instalar TriliumNext en su servidor (incluyendo vía Docker desde [Dockerhub](https://hub.docker.com/r/triliumnext/notes)) siga la [documentación de instalación de servidor](https://triliumnext.github.io/Docs/Wiki/server-installation).
|
||||
|
||||
## 📝 Documentación
|
||||
|
||||
[Vea la Wiki para la lista completa de páginas de documentación.](https://triliumnext.github.io/Docs)
|
||||
|
||||
También puede leer [Patrones para una base de conocimiento personal](https://triliumnext.github.io/Docs/Wiki/patterns-of-personal-knowledge) para obtener un poco de inspiración de como podría usar TriliumNext.
|
||||
|
||||
## 💻 Contribuir
|
||||
|
||||
Clone localmente y ejecute
|
||||
|
||||
```shell
|
||||
npm install
|
||||
npm run start-server
|
||||
```
|
||||
|
||||
## 👏 Reconocimientos
|
||||
|
||||
- [CKEditor 5](https://github.com/ckeditor/ckeditor5) - el mejor editor WYSIWYG en el mercado, equipo muy interactivo y atento
|
||||
- [FancyTree](https://github.com/mar10/fancytree) - biblioteca de árbol muy rica en funciones sin competencia real. TriliumNext Notes no sería lo mismo sin esta.
|
||||
- [CodeMirror](https://github.com/codemirror/CodeMirror) - editor de código con soporte para una gran cantidad de lenguajes
|
||||
- [jsPlumb](https://github.com/jsplumb/jsplumb) - biblioteca de conectividad visual sin competencia. Usado en [mapas de relación](https://triliumnext.github.io/Docs/Wiki/Relation-map) y [mapas de enlace](https://triliumnext.github.io/Docs/Wiki/Link-map)
|
||||
|
||||
## 🤝 Soporte
|
||||
|
||||
Puede apoyar al desarrollador original de Trilium usando GitHub Sponsors, [PayPal](https://paypal.me/za4am) o Bitcoin (bitcoin:bc1qv3svjn40v89mnkre5vyvs2xw6y8phaltl385d2).
|
||||
Apoyo para la organización TriliumNext será posible en un futuro próximo.
|
||||
|
||||
## 🔑 Licencia
|
||||
|
||||
Este programa es software libre: puede redistribuirlo y/o modificarlo bajo los términos de la Licencia Pública General de Affero GNU publicada por la Free Software Foundation, ya sea la versión 3 de la Licencia, o (a su elección) cualquier versión posterior.
|
||||
@@ -1,6 +1,6 @@
|
||||
# TriliumNext Notes
|
||||
|
||||
[English](https://github.com/TriliumNext/Notes/blob/master/README.md) | [Chinese](https://github.com/TriliumNext/Notes/blob/master/README-ZH_CN.md) | [Russian](https://github.com/TriliumNext/Notes/blob/master/README.ru.md) | [Japanese](https://github.com/TriliumNext/Notes/blob/master/README.ja.md) | [Italian](https://github.com/TriliumNext/Notes/blob/master/README.it.md)
|
||||
[English](./README.md) | [Chinese](./README-ZH_CN.md) | [Russian](./README.ru.md) | [Japanese](./README.ja.md) | [Italian](./README.it.md) | [Spanish](./README.es.md)
|
||||
|
||||
TriliumNext Notes è un'applicazione per appunti ad organizzazione gerarchica, studiata per la costruzione di archivi di conoscenza personali di grandi dimensioni.
|
||||
|
||||
@@ -70,7 +70,8 @@ Puoi anche leggere ["Patterns of personal knowledge base"](https://triliumnext.g
|
||||
## 💻 Contribuire
|
||||
|
||||
Clona localmente ed esegui
|
||||
```
|
||||
|
||||
```shell
|
||||
npm install
|
||||
npm run start-server
|
||||
```
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# TriliumNext Notes
|
||||
|
||||
[English](https://github.com/TriliumNext/Notes/blob/master/README.md) | [Chinese](https://github.com/TriliumNext/Notes/blob/master/README-ZH_CN.md) | [Russian](https://github.com/TriliumNext/Notes/blob/master/README.ru.md) | [Japanese](https://github.com/TriliumNext/Notes/blob/master/README.ja.md) | [Italian](https://github.com/TriliumNext/Notes/blob/master/README.it.md)
|
||||
[English](./README.md) | [Chinese](./README-ZH_CN.md) | [Russian](./README.ru.md) | [Japanese](./README.ja.md) | [Italian](./README.it.md) | [Spanish](./README.es.md)
|
||||
|
||||
Trilium Notes は、大規模な個人知識ベースの構築に焦点を当てた、階層型ノートアプリケーションです。概要は[スクリーンショット](https://triliumnext.github.io/Docs/Wiki/screenshot-tour)をご覧ください:
|
||||
|
||||
@@ -51,7 +51,8 @@ Trilium は Flatpak としても提供されます:
|
||||
## 💻 コントリビュート
|
||||
|
||||
または、ローカルにクローンして実行
|
||||
```
|
||||
|
||||
```shell
|
||||
npm install
|
||||
npm run start-server
|
||||
```
|
||||
|
||||
60
README.md
@@ -1,8 +1,8 @@
|
||||
# TriliumNext Notes
|
||||
|
||||
[English](https://github.com/TriliumNext/Notes/blob/master/README.md) | [Chinese](https://github.com/TriliumNext/Notes/blob/master/README-ZH_CN.md) | [Russian](https://github.com/TriliumNext/Notes/blob/master/README.ru.md) | [Japanese](https://github.com/TriliumNext/Notes/blob/master/README.ja.md) | [Italian](https://github.com/TriliumNext/Notes/blob/master/README.it.md)
|
||||
[English](./README.md) | [Chinese](./README-ZH_CN.md) | [Russian](./README.ru.md) | [Japanese](./README.ja.md) | [Italian](./README.it.md) | [Spanish](./README.es.md)
|
||||
|
||||
TriliumNext Notes is a hierarchical note taking application with focus on building large personal knowledge bases.
|
||||
TriliumNext Notes is an open-source, cross-platform hierarchical note taking application with focus on building large personal knowledge bases.
|
||||
|
||||
See [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) for quick overview:
|
||||
|
||||
@@ -12,23 +12,22 @@ See [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) for q
|
||||
|
||||
[The original Trilium project is in maintenance mode](https://github.com/zadam/trilium/issues/4620)
|
||||
|
||||
### Migrating from Trilium?
|
||||
|
||||
There are no special migration steps to migrate from a zadam/Trilium instance to a TriliumNext/Notes instance. Just upgrade your Trilium instance to the latest version and [install TriliumNext/Notes as usual](#-installation)
|
||||
|
||||
## 💬 Discuss with us
|
||||
|
||||
Feel free to join our official discussions and community. We are focused on the development on Trilium, and would love to hear what features, suggestions, or issues you may have!
|
||||
Feel free to join our official conversations. We would love to hear what features, suggestions, or issues you may have!
|
||||
|
||||
- [Matrix](https://matrix.to/#/#triliumnext:matrix.org) (For synchronous discussions)
|
||||
- The `General` Matrix room is also bridged to [XMPP](xmpp:discuss@trilium.thisgreat.party?join)
|
||||
- [Github Discussions](https://github.com/TriliumNext/Notes/discussions) (For Asynchronous discussions)
|
||||
- [Wiki](https://triliumnext.github.io/Docs/) (For common how-to questions and user guides)
|
||||
|
||||
The two rooms linked above are mirrored, so you can use either XMPP or Matrix, from any client you prefer, on pretty much any platform under the sun!
|
||||
|
||||
### Unofficial Communities
|
||||
|
||||
[Trilium Rocks](https://discord.gg/aqdX9mXX4r)
|
||||
|
||||
## 🎁 Features
|
||||
|
||||
* Notes can be arranged into arbitrarily deep tree. Single note can be placed into multiple places in the tree (see [cloning](https://triliumnext.github.io/Docs/Wiki/cloning-notes)
|
||||
* Notes can be arranged into arbitrarily deep tree. Single note can be placed into multiple places in the tree (see [cloning](https://triliumnext.github.io/Docs/Wiki/cloning-notes))
|
||||
* Rich WYSIWYG note editing including e.g. tables, images and [math](https://triliumnext.github.io/Docs/Wiki/text-notes) with markdown [autoformat](https://triliumnext.github.io/Docs/Wiki/text-notes#autoformat)
|
||||
* Support for editing [notes with source code](https://triliumnext.github.io/Docs/Wiki/code-notes), including syntax highlighting
|
||||
* Fast and easy [navigation between notes](https://triliumnext.github.io/Docs/Wiki/note-navigation), full text search and [note hoisting](https://triliumnext.github.io/Docs/Wiki/note-hoisting)
|
||||
@@ -48,41 +47,58 @@ The two rooms linked above are mirrored, so you can use either XMPP or Matrix, f
|
||||
* [Evernote](https://triliumnext.github.io/Docs/Wiki/evernote-import) and [Markdown import & export](https://triliumnext.github.io/Docs/Wiki/markdown)
|
||||
* [Web Clipper](https://triliumnext.github.io/Docs/Wiki/web-clipper) for easy saving of web content
|
||||
|
||||
✨ Check out the following third-party resources for more TriliumNext related goodies:
|
||||
✨ Check out the following third-party resources/communities for more TriliumNext related goodies:
|
||||
|
||||
- [awesome-trilium](https://github.com/Nriver/awesome-trilium) for 3rd party themes, scripts, plugins and more.
|
||||
- [TriliumRocks!](https://trilium.rocks/) for tutorials, guides, and much more.
|
||||
|
||||
## 🏗 Builds
|
||||
## 🏗 Installation
|
||||
|
||||
Trilium is provided as either desktop application (Linux and Windows) or web application hosted on your server (Linux). Mac OS desktop build is available, but it is [unsupported](https://triliumnext.github.io/Docs/Wiki/faq#mac-os-support).
|
||||
### Desktop
|
||||
|
||||
* If you want to use TriliumNext on the desktop, download binary release for your platform from [latest release](https://github.com/TriliumNext/Notes/releases/latest), unzip the package and run ```trilium``` executable.
|
||||
* If you want to install TriliumNext on your own server, follow [this page](https://triliumnext.github.io/Docs/Wiki/server-installation).
|
||||
* Currently only recent versions of Chrome and Firefox are supported (tested) browsers.
|
||||
To use TriliumNext on your desktop machine (Linux, MacOS, and Windows) you have a few options:
|
||||
|
||||
TriliumNext will also provided as a Flatpak:
|
||||
* Download the binary release for your platform from the [latest release page](https://github.com/TriliumNext/Notes/releases/latest), unzip the package and run the ```trilium``` executable.
|
||||
* Access TriliumNext via the web interface of a server installation (see below)
|
||||
* Currently only the latest versions of Chrome & Firefox are supported (and tested).
|
||||
* (Coming Soon) TriliumNext will also be provided as a Flatpak
|
||||
|
||||
<img width="240" src="https://flathub.org/assets/badges/flathub-badge-en.png">
|
||||
### Mobile
|
||||
|
||||
To use TriliumNext on a mobile device:
|
||||
|
||||
* Use a mobile web browser to access the mobile interface of a server installation (see below)
|
||||
* Use of a mobile app is not yet supported ([see here](https://github.com/TriliumNext/Notes/issues/72)) to track mobile improvements.
|
||||
|
||||
### Server
|
||||
|
||||
To install TriliumNext on your own server (including via Docker from [Dockerhub](https://hub.docker.com/r/triliumnext/notes)) follow [the server installation docs](https://triliumnext.github.io/Docs/Wiki/server-installation).
|
||||
|
||||
## 📝 Documentation
|
||||
|
||||
[See wiki for complete list of documentation pages.](https://triliumnext.github.io/Docs)
|
||||
|
||||
You can also read [Patterns of personal knowledge base](https://triliumnext.github.io/Docs/Wiki/patterns-of-personal-knowledge) to get some inspiration on how you might use Trilium.
|
||||
You can also read [Patterns of personal knowledge base](https://triliumnext.github.io/Docs/Wiki/patterns-of-personal-knowledge) to get some inspiration on how you might use TriliumNext.
|
||||
|
||||
## 💻 Contribute
|
||||
|
||||
Clone locally and run
|
||||
```
|
||||
### Code
|
||||
|
||||
```shell
|
||||
git clone https://github.com/TriliumNext/Notes.git
|
||||
cd Notes
|
||||
npm install
|
||||
npm run start-server
|
||||
```
|
||||
|
||||
### Documentation
|
||||
|
||||
Head on over to our [Docs repo](https://github.com/TriliumNext/Docs)
|
||||
|
||||
## 👏 Shoutouts
|
||||
|
||||
* [CKEditor 5](https://github.com/ckeditor/ckeditor5) - best WYSIWYG editor on the market, very interactive and listening team
|
||||
* [FancyTree](https://github.com/mar10/fancytree) - very feature rich tree library without real competition. Trilium Notes would not be the same without it.
|
||||
* [FancyTree](https://github.com/mar10/fancytree) - very feature rich tree library without real competition. TriliumNext Notes would not be the same without it.
|
||||
* [CodeMirror](https://github.com/codemirror/CodeMirror) - code editor with support for huge amount of languages
|
||||
* [jsPlumb](https://github.com/jsplumb/jsplumb) - visual connectivity library without competition. Used in [relation maps](https://triliumnext.github.io/Docs/Wiki/Relation-map) and [link maps](https://triliumnext.github.io/Docs/Wiki/Link-map)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# TriliumNext Notes
|
||||
|
||||
[English](https://github.com/TriliumNext/Notes/blob/master/README.md) | [Chinese](https://github.com/TriliumNext/Notes/blob/master/README-ZH_CN.md) | [Russian](https://github.com/TriliumNext/Notes/blob/master/README.ru.md) | [Japanese](https://github.com/TriliumNext/Notes/blob/master/README.ja.md) | [Italian](https://github.com/TriliumNext/Notes/blob/master/README.it.md)
|
||||
[English](./README.md) | [Chinese](./README-ZH_CN.md) | [Russian](./README.ru.md) | [Japanese](./README.ja.md) | [Italian](./README.it.md) | [Spanish](./README.es.md)
|
||||
|
||||
Trilium Notes – это приложение для заметок с иерархической структурой, ориентированное на создание больших персональных баз знаний. Для быстрого ознакомления посмотрите [скриншот-тур](https://triliumnext.github.io/Docs/Wiki/screenshot-tour):
|
||||
|
||||
@@ -41,7 +41,8 @@ Trilium предоставляется в виде десктопного при
|
||||
## 💻 Участвуйте в разработке
|
||||
|
||||
Или склонируйте на своё устройство и запустите
|
||||
```
|
||||
|
||||
```shell
|
||||
npm install
|
||||
npm run start-server
|
||||
```
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
ELECTRON_VERSION="electron-v125"
|
||||
NODE_VERSION="node-v115"
|
||||
|
||||
if ! command -v jq &> /dev/null; then
|
||||
echo "Missing command: jq"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
script_dir=$(realpath $(dirname $0))
|
||||
cd "$script_dir"
|
||||
BETTER_SQLITE3_VERSION=$(jq -r '.dependencies.["better-sqlite3"]' ../../package.json | grep -oP "\d+\.\d+\.\d+")
|
||||
|
||||
if [ -z $BETTER_SQLITE3_VERSION ]; then
|
||||
echo "Unable to determine better-sqlite3 version."
|
||||
exit 2
|
||||
fi
|
||||
|
||||
echo "Version: $BETTER_SQLITE3_VERSION"
|
||||
|
||||
function download() {
|
||||
version="$1"
|
||||
platform="$2"
|
||||
dest_name="$3"
|
||||
url=https://github.com/WiseLibs/better-sqlite3/releases/download/v${BETTER_SQLITE3_VERSION}/better-sqlite3-v${BETTER_SQLITE3_VERSION}-${version}-${platform}.tar.gz
|
||||
temp_file="temp.tar.gz"
|
||||
curl -L "$url" -o "$temp_file"
|
||||
tar -xzvf "$temp_file"
|
||||
mv build/Release/better_sqlite3.node "$dest_name-better_sqlite3.node"
|
||||
rm -rf build
|
||||
rm -f "$temp_file"
|
||||
}
|
||||
|
||||
download $NODE_VERSION "linux-x64" "linux-server"
|
||||
download $ELECTRON_VERSION "linux-x64" "linux-desktop"
|
||||
download $ELECTRON_VERSION "win32-x64" "win"
|
||||
download $ELECTRON_VERSION "darwin-x64" "mac-x64"
|
||||
download $ELECTRON_VERSION "darwin-arm64" "mac-arm64"
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e # Fail on any command error
|
||||
|
||||
if ! command -v dpkg-deb &> /dev/null; then
|
||||
echo "Missing command: dpkg-deb"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if dpkg-deb 2>&1 | grep BusyBox &> /dev/null; then
|
||||
echo "The dpkg-deb binary provided by BusyBox is not compatible. The Debian tool needs to be used instead."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Packaging debian x64 distribution..."
|
||||
|
||||
VERSION=`jq -r ".version" package.json`
|
||||
|
||||
./node_modules/.bin/electron-installer-debian --config bin/deb-options.json --options.version=${VERSION} --arch amd64
|
||||
@@ -10,8 +10,8 @@ cat package.json | grep -v electron > server-package.json
|
||||
echo "Compiling typescript..."
|
||||
npx tsc
|
||||
|
||||
sudo docker build -t zadam/trilium:$VERSION --network host -t zadam/trilium:$SERIES .
|
||||
sudo docker build -t triliumnext/notes:$VERSION --network host -t triliumnext/notes:$SERIES .
|
||||
|
||||
if [[ $VERSION != *"beta"* ]]; then
|
||||
sudo docker tag zadam/trilium:$VERSION zadam/trilium:latest
|
||||
sudo docker tag triliumnext/notes:$VERSION triliumnext/notes:latest
|
||||
fi
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e # Fail on any command error
|
||||
|
||||
if ! command -v jq &> /dev/null; then
|
||||
echo "Missing command: jq"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v fakeroot &> /dev/null; then
|
||||
echo "Missing command: fakeroot"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v dpkg-deb &> /dev/null; then
|
||||
echo "Missing command: dpkg-deb"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if dpkg-deb 2>&1 | grep BusyBox &> /dev/null; then
|
||||
echo "The dpkg-deb binary provided by BusyBox is not compatible. The Debian tool needs to be used instead."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SRC_DIR=./dist/trilium-linux-x64-src
|
||||
|
||||
[ "$1" != "DONTCOPY" ] && ./bin/copy-trilium.sh "$SRC_DIR"
|
||||
|
||||
echo "Copying required linux-x64 binaries"
|
||||
cp -r bin/better-sqlite3/linux-desktop-better_sqlite3.node "$SRC_DIR"/node_modules/better-sqlite3/build/Release/better_sqlite3.node
|
||||
|
||||
echo "Packaging linux x64 electron build"
|
||||
./node_modules/.bin/electron-packager "$SRC_DIR" --asar --out=dist --executable-name=trilium --platform=linux --arch=x64 --overwrite
|
||||
|
||||
BUILD_DIR=./dist/trilium-linux-x64
|
||||
rm -rf "$BUILD_DIR"
|
||||
|
||||
mv "./dist/TriliumNext Notes-linux-x64" "$BUILD_DIR"
|
||||
|
||||
cp images/app-icons/png/128x128.png "$BUILD_DIR"/icon.png
|
||||
cp bin/tpl/anonymize-database.sql "$BUILD_DIR"/
|
||||
|
||||
cp -r dump-db "$BUILD_DIR"/
|
||||
rm -rf "$BUILD_DIR"/dump-db/node_modules
|
||||
|
||||
for f in 'trilium-portable' 'trilium-safe-mode' 'trilium-no-cert-check'; do
|
||||
cp bin/tpl/"$f".sh "$BUILD_DIR"/
|
||||
chmod 755 "$BUILD_DIR"/"$f".sh
|
||||
done
|
||||
|
||||
echo "Packaging linux x64 electron distribution..."
|
||||
VERSION=`jq -r ".version" package.json`
|
||||
|
||||
pushd dist
|
||||
tar cJf "trilium-linux-x64-${VERSION}.tar.xz" trilium-linux-x64
|
||||
popd
|
||||
|
||||
bin/build-debian.sh
|
||||
@@ -1,37 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e # Fail on any command error
|
||||
|
||||
SRC_DIR=./dist/trilium-mac-arm64-src
|
||||
|
||||
if [ "$1" != "DONTCOPY" ]
|
||||
then
|
||||
./bin/copy-trilium.sh $SRC_DIR
|
||||
fi
|
||||
|
||||
echo "Copying required mac arm64 binaries"
|
||||
|
||||
cp -r bin/better-sqlite3/mac-arm64-better_sqlite3.node $SRC_DIR/node_modules/better-sqlite3/build/Release/better_sqlite3.node
|
||||
|
||||
echo "Packaging mac arm64 electron build"
|
||||
|
||||
./node_modules/.bin/electron-packager $SRC_DIR --asar --out=dist --executable-name=trilium --platform=darwin --arch=arm64 --overwrite --icon=images/app-icons/mac/icon.icns
|
||||
|
||||
BUILD_DIR=./dist/trilium-mac-arm64
|
||||
rm -rf $BUILD_DIR
|
||||
|
||||
# Mac build has by default useless directory level
|
||||
mv "./dist/TriliumNext Notes-darwin-arm64" $BUILD_DIR
|
||||
|
||||
cp bin/tpl/anonymize-database.sql $BUILD_DIR/
|
||||
|
||||
cp -r dump-db $BUILD_DIR/
|
||||
rm -rf $BUILD_DIR/dump-db/node_modules
|
||||
|
||||
echo "Zipping mac arm64 electron distribution..."
|
||||
|
||||
VERSION=`jq -r ".version" package.json`
|
||||
|
||||
cd dist
|
||||
|
||||
zip -r9 --symlinks trilium-mac-arm64-${VERSION}.zip trilium-mac-arm64
|
||||
@@ -1,37 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e # Fail on any command error
|
||||
|
||||
SRC_DIR=./dist/trilium-mac-x64-src
|
||||
|
||||
if [ "$1" != "DONTCOPY" ]
|
||||
then
|
||||
./bin/copy-trilium.sh $SRC_DIR
|
||||
fi
|
||||
|
||||
echo "Copying required mac x64 binaries"
|
||||
|
||||
cp -r bin/better-sqlite3/mac-x64-better_sqlite3.node $SRC_DIR/node_modules/better-sqlite3/build/Release/better_sqlite3.node
|
||||
|
||||
echo "Packaging mac x64 electron build"
|
||||
|
||||
./node_modules/.bin/electron-packager $SRC_DIR --asar --out=dist --executable-name=trilium --platform=darwin --arch=x64 --overwrite --icon=images/app-icons/mac/icon.icns
|
||||
|
||||
BUILD_DIR=./dist/trilium-mac-x64
|
||||
rm -rf $BUILD_DIR
|
||||
|
||||
# Mac build has by default useless directory level
|
||||
mv "./dist/TriliumNext Notes-darwin-x64" $BUILD_DIR
|
||||
|
||||
cp bin/tpl/anonymize-database.sql $BUILD_DIR/
|
||||
|
||||
cp -r dump-db $BUILD_DIR/
|
||||
rm -rf $BUILD_DIR/dump-db/node_modules
|
||||
|
||||
echo "Zipping mac x64 electron distribution..."
|
||||
|
||||
VERSION=`jq -r ".version" package.json`
|
||||
|
||||
cd dist
|
||||
|
||||
zip -r9 --symlinks trilium-mac-x64-${VERSION}.zip trilium-mac-x64
|
||||
@@ -22,9 +22,7 @@ rm -r $PKG_DIR/node/lib/node_modules/npm
|
||||
rm -r $PKG_DIR/node/include/node
|
||||
|
||||
rm -r $PKG_DIR/node_modules/electron*
|
||||
rm -r $PKG_DIR/electron.js
|
||||
|
||||
cp -r bin/better-sqlite3/linux-server-better_sqlite3.node $PKG_DIR/node_modules/better-sqlite3/build/Release/better_sqlite3.node
|
||||
rm -r $PKG_DIR/electron*.js
|
||||
|
||||
printf "#!/bin/sh\n./node/bin/node src/www" > $PKG_DIR/trilium.sh
|
||||
chmod 755 $PKG_DIR/trilium.sh
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e # Fail on any command error
|
||||
|
||||
if ! command -v wine &> /dev/null; then
|
||||
echo "Missing command: wine"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SRC_DIR=./dist/trilium-windows-x64-src
|
||||
|
||||
if [ "$1" != "DONTCOPY" ]
|
||||
then
|
||||
./bin/copy-trilium.sh $SRC_DIR
|
||||
fi
|
||||
|
||||
echo "Copying required windows binaries"
|
||||
|
||||
cp -r bin/better-sqlite3/win-better_sqlite3.node $SRC_DIR/node_modules/better-sqlite3/build/Release/better_sqlite3.node
|
||||
|
||||
echo "Packaging windows x64 electron build"
|
||||
|
||||
./node_modules/.bin/electron-packager $SRC_DIR --asar --out=dist --executable-name=trilium --platform=win32 --arch=x64 --overwrite --icon=images/app-icons/win/icon.ico
|
||||
|
||||
BUILD_DIR=./dist/trilium-windows-x64
|
||||
rm -rf $BUILD_DIR
|
||||
|
||||
mv "./dist/TriliumNext Notes-win32-x64" $BUILD_DIR
|
||||
|
||||
cp bin/tpl/anonymize-database.sql $BUILD_DIR/
|
||||
|
||||
cp -r dump-db $BUILD_DIR/
|
||||
rm -rf $BUILD_DIR/dump-db/node_modules
|
||||
|
||||
cp bin/tpl/trilium-{portable,no-cert-check,safe-mode}.bat $BUILD_DIR/
|
||||
|
||||
if [ "$1" != "DONTPACK" ]
|
||||
then
|
||||
echo "Zipping windows x64 electron distribution..."
|
||||
VERSION=`jq -r ".version" package.json`
|
||||
|
||||
cd dist
|
||||
zip -r9 trilium-windows-x64-${VERSION}.zip trilium-windows-x64
|
||||
fi
|
||||
@@ -75,7 +75,21 @@ const copy = async () => {
|
||||
"node_modules/split.js/dist/",
|
||||
"node_modules/panzoom/dist/",
|
||||
"node_modules/i18next/",
|
||||
"node_modules/i18next-http-backend/"
|
||||
"node_modules/i18next-http-backend/",
|
||||
"node_modules/eslint/bin/",
|
||||
"node_modules/jsplumb/dist/",
|
||||
"node_modules/vanilla-js-wheel-zoom/dist/",
|
||||
"node_modules/mark.js/dist/",
|
||||
"node_modules/knockout/build/output/",
|
||||
"node_modules/normalize.css/",
|
||||
"node_modules/jquery.fancytree/dist/",
|
||||
"node_modules/bootstrap/dist/",
|
||||
"node_modules/autocomplete.js/dist/",
|
||||
"node_modules/codemirror/lib/",
|
||||
"node_modules/codemirror/addon/",
|
||||
"node_modules/codemirror/mode/",
|
||||
"node_modules/codemirror/keymap/",
|
||||
"node_modules/mind-elixir/dist/"
|
||||
];
|
||||
|
||||
for (const folder of nodeModulesFolder) {
|
||||
|
||||
@@ -37,11 +37,11 @@ for f in 'package.json' 'package-lock.json' 'README.md' 'LICENSE' 'config-sample
|
||||
done
|
||||
|
||||
# Patch package.json main
|
||||
sed -i 's/.\/dist\/electron.js/electron.js/g' "$DIR/package.json"
|
||||
sed -i 's/.\/dist\/electron-main.js/electron-main.js/g' "$DIR/package.json"
|
||||
|
||||
script_dir=$(realpath $(dirname $0))
|
||||
cp -R "$script_dir/../build/src" "$DIR"
|
||||
cp "$script_dir/../build/electron.js" "$DIR"
|
||||
cp "$script_dir/../build/electron-main.js" "$DIR"
|
||||
|
||||
# run in subshell (so we return to original dir)
|
||||
(cd $DIR && npm install --omit=dev)
|
||||
@@ -52,7 +52,6 @@ if [[ -d "$DIR"/node_modules ]]; then
|
||||
'@excalidraw/excalidraw/dist/excalidraw-assets-dev' '@excalidraw/excalidraw/dist/excalidraw.development.js' '@excalidraw/excalidraw/dist/excalidraw-with-preact.development.js' \
|
||||
'mermaid/dist/mermaid.js' \
|
||||
'boxicons/svg' 'boxicons/node_modules/react'/* \
|
||||
'better-sqlite3/Release' 'better-sqlite3/deps/sqlite3.tar.gz' 'better-sqlite3/deps/sqlite3' \
|
||||
'@jimp/plugin-print/fonts' 'jimp/browser' 'jimp/fonts'; do
|
||||
[[ -e "$DIR"/node_modules/"$d" ]] && rm -r "$DIR"/node_modules/"$d"
|
||||
done
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const anonymizationService = require('../src/services/anonymization');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
import anonymizationService from '../src/services/anonymization.js';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
fs.writeFileSync(path.resolve(__dirname, 'tpl', 'anonymize-database.sql'), anonymizationService.getFullAnonymizationScript());
|
||||
@@ -39,7 +39,7 @@ done
|
||||
icnsutil compose -f "mac/icon.icns" ./mac/*.png
|
||||
|
||||
# Build Windows icon
|
||||
magick -background none "../icon-color.svg" -define icon:auto-resize=16,32,48,64,128,256 "./win/icon.ico"
|
||||
magick -background none "../icon-color.svg" -define icon:auto-resize=16,32,48,64,128,256 "./icon.ico"
|
||||
|
||||
# Build Squirrel splash image
|
||||
magick "./png/256x256.png" -background "#ffffff" -gravity center -extent 640x480 "./win/setup-banner.gif"
|
||||
@@ -47,35 +47,3 @@ echo "Tagging commit with $TAG"
|
||||
|
||||
git tag $TAG
|
||||
git push origin $TAG
|
||||
|
||||
bin/build.sh
|
||||
|
||||
LINUX_X64_BUILD=trilium-linux-x64-$VERSION.tar.xz
|
||||
DEBIAN_X64_BUILD=trilium_${VERSION}_amd64.deb
|
||||
WINDOWS_X64_BUILD=trilium-windows-x64-$VERSION.zip
|
||||
MAC_X64_BUILD=trilium-mac-x64-$VERSION.zip
|
||||
MAC_ARM64_BUILD=trilium-mac-arm64-$VERSION.zip
|
||||
SERVER_BUILD=trilium-linux-x64-server-$VERSION.tar.xz
|
||||
|
||||
echo "Creating release in GitHub"
|
||||
|
||||
EXTRA=
|
||||
|
||||
if [[ $TAG == *"beta"* ]]; then
|
||||
EXTRA=--prerelease
|
||||
fi
|
||||
|
||||
if [ ! -z "$GITHUB_CLI_AUTH_TOKEN" ]; then
|
||||
echo "$GITHUB_CLI_AUTH_TOKEN" | gh auth login --with-token
|
||||
fi
|
||||
|
||||
gh release create -d "$TAG" \
|
||||
--title "$TAG release" \
|
||||
--notes "" \
|
||||
$EXTRA \
|
||||
"dist/$DEBIAN_X64_BUILD" \
|
||||
"dist/$LINUX_X64_BUILD" \
|
||||
"dist/$WINDOWS_X64_BUILD" \
|
||||
"dist/$MAC_X64_BUILD" \
|
||||
"dist/$MAC_ARM64_BUILD" \
|
||||
"dist/$SERVER_BUILD"
|
||||
|
||||
BIN
db/demo.zip
@@ -1,16 +1,21 @@
|
||||
# Running `docker-compose up` will create/use the "trilium-data" directory in the user home
|
||||
# Run `TRILIUM_DATA_DIR=/path/of/your/choice docker-compose up` to set a different directory
|
||||
version: '2.1'
|
||||
# To run in the background, use `docker-compose up -d`
|
||||
services:
|
||||
trilium:
|
||||
image: zadam/trilium
|
||||
restart: always
|
||||
# Optionally, replace `latest` with a version tag like `v0.90.3`
|
||||
# Using `latest` may cause unintended updates to the container
|
||||
image: triliumnext/notes:latest
|
||||
# Restart the container unless it was stopped by the user
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- TRILIUM_DATA_DIR=/home/node/trilium-data
|
||||
ports:
|
||||
- "8080:8080"
|
||||
# By default, Trilium will be available at http://localhost:8080
|
||||
# It will also be accessible at http://<host-ip>:8080
|
||||
# You might want to limit this with something like Docker Networks, reverse proxies, or firewall rules, such as UFW
|
||||
- '8080:8080'
|
||||
volumes:
|
||||
# Unless TRILIUM_DATA_DIR is set, the data will be stored in the "trilium-data" directory in the home directory.
|
||||
# This can also be changed with by replacing the line below with `- /path/of/your/choice:/home/node/trilium-data
|
||||
- ${TRILIUM_DATA_DIR:-~/trilium-data}:/home/node/trilium-data
|
||||
|
||||
volumes:
|
||||
trilium:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const http = require("http");
|
||||
const ini = require("ini");
|
||||
const fs = require("fs");
|
||||
const dataDir = require('./src/services/data_dir');
|
||||
import http from "http";
|
||||
import ini from "ini";
|
||||
import fs from "fs";
|
||||
import dataDir from './src/services/data_dir.js';
|
||||
const config = ini.parse(fs.readFileSync(dataDir.CONFIG_INI_PATH, 'utf-8'));
|
||||
|
||||
if (config.Network.https) {
|
||||
@@ -10,12 +10,12 @@ if (config.Network.https) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const port = require('./src/services/port');
|
||||
const host = require('./src/services/host');
|
||||
import port from './src/services/port.js';
|
||||
import host from './src/services/host.js';
|
||||
|
||||
const options = { timeout: 2000 };
|
||||
const options: http.RequestOptions = { timeout: 2000 };
|
||||
|
||||
const callback = res => {
|
||||
const callback: (res: http.IncomingMessage) => void = res => {
|
||||
console.log(`STATUS: ${res.statusCode}`);
|
||||
if (res.statusCode === 200) {
|
||||
process.exit(0);
|
||||
@@ -42,9 +42,9 @@ const NOTE_TYPE_ICONS = {
|
||||
"code": "bx bx-code",
|
||||
"render": "bx bx-extension",
|
||||
"search": "bx bx-file-find",
|
||||
"relationMap": "bx bx-map-alt",
|
||||
"relationMap": "bx bxs-network-chart",
|
||||
"book": "bx bx-book",
|
||||
"noteMap": "bx bx-map-alt",
|
||||
"noteMap": "bx bxs-network-chart",
|
||||
"mermaid": "bx bx-selection",
|
||||
"canvas": "bx bx-pen",
|
||||
"webView": "bx bx-globe-alt",
|
||||
@@ -570,7 +570,7 @@ class FNote {
|
||||
return workspaceIconClass;
|
||||
}
|
||||
else if (this.noteId === 'root') {
|
||||
return "bx bx-chevrons-right";
|
||||
return "bx bx-home-alt-2";
|
||||
}
|
||||
if (this.noteId === '_share') {
|
||||
return "bx bx-share-alt";
|
||||
|
||||
@@ -14,10 +14,10 @@ npm install
|
||||
|
||||
## Running
|
||||
|
||||
See output of `node dump-db.js --help`:
|
||||
See output of `npx esrun dump.ts --help`:
|
||||
|
||||
```
|
||||
dump-db.js <path_to_document> <target_directory>
|
||||
dump-db.ts <path_to_document> <target_directory>
|
||||
|
||||
dump the contents of document.db into the target directory
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const yargs = require('yargs/yargs')
|
||||
const { hideBin } = require('yargs/helpers')
|
||||
const dumpService = require('./inc/dump.js');
|
||||
import yargs from 'yargs';
|
||||
import { hideBin } from 'yargs/helpers';
|
||||
import dumpService from './inc/dump.js';
|
||||
|
||||
yargs(hideBin(process.argv))
|
||||
.command('$0 <path_to_document> <target_directory>', 'dump the contents of document.db into the target directory', (yargs) => {
|
||||
return yargs
|
||||
.positional('path_to_document', { describe: 'path to the document.db' })
|
||||
.positional('target_directory', { describe: 'path of the directory into which the notes should be dumped' })
|
||||
.option('path_to_document', { alias: 'p', describe: 'path to the document.db', type: 'string', demandOption: true })
|
||||
.option('target_directory', { alias: 't', describe: 'path of the directory into which the notes should be dumped', type: 'string', demandOption: true });
|
||||
}, (argv) => {
|
||||
try {
|
||||
dumpService.dumpDocument(argv.path_to_document, argv.target_directory, {
|
||||
@@ -1,8 +1,8 @@
|
||||
const crypto = require("crypto");
|
||||
const sql = require('./sql');
|
||||
const decryptService = require('./decrypt.js');
|
||||
import crypto from 'crypto';
|
||||
import sql from './sql.js';
|
||||
import decryptService from './decrypt.js';
|
||||
|
||||
function getDataKey(password) {
|
||||
function getDataKey(password: any) {
|
||||
if (!password) {
|
||||
return null;
|
||||
}
|
||||
@@ -16,28 +16,28 @@ function getDataKey(password) {
|
||||
|
||||
return decryptedDataKey;
|
||||
}
|
||||
catch (e) {
|
||||
catch (e: any) {
|
||||
throw new Error(`Cannot read data key, the entered password might be wrong. The underlying error: '${e.message}', stack:\n${e.stack}`);
|
||||
}
|
||||
}
|
||||
|
||||
function getPasswordDerivedKey(password) {
|
||||
function getPasswordDerivedKey(password: any) {
|
||||
const salt = getOption('passwordDerivedKeySalt');
|
||||
|
||||
return getScryptHash(password, salt);
|
||||
}
|
||||
|
||||
function getScryptHash(password, salt) {
|
||||
function getScryptHash(password: any, salt: any) {
|
||||
const hashed = crypto.scryptSync(password, salt, 32,
|
||||
{N: 16384, r:8, p:1});
|
||||
{ N: 16384, r: 8, p: 1 });
|
||||
|
||||
return hashed;
|
||||
}
|
||||
|
||||
function getOption(name) {
|
||||
function getOption(name: string) {
|
||||
return sql.getValue("SELECT value FROM options WHERE name = ?", [name]);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
getDataKey
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
const crypto = require("crypto");
|
||||
import crypto from 'crypto';
|
||||
|
||||
function decryptString(dataKey, cipherText) {
|
||||
function decryptString(dataKey: any, cipherText: any) {
|
||||
const buffer = decrypt(dataKey, cipherText);
|
||||
|
||||
if (buffer === null) {
|
||||
@@ -16,7 +16,7 @@ function decryptString(dataKey, cipherText) {
|
||||
return str;
|
||||
}
|
||||
|
||||
function decrypt(key, cipherText, ivLength = 13) {
|
||||
function decrypt(key: any, cipherText: any, ivLength = 13) {
|
||||
if (cipherText === null) {
|
||||
return null;
|
||||
}
|
||||
@@ -46,11 +46,10 @@ function decrypt(key, cipherText, ivLength = 13) {
|
||||
|
||||
return payload;
|
||||
}
|
||||
catch (e) {
|
||||
catch (e: any) {
|
||||
// recovery from https://github.com/zadam/trilium/issues/510
|
||||
if (e.message?.includes("WRONG_FINAL_BLOCK_LENGTH") || e.message?.includes("wrong final block length")) {
|
||||
log.info("Caught WRONG_FINAL_BLOCK_LENGTH, returning cipherText instead");
|
||||
|
||||
console.log("Caught WRONG_FINAL_BLOCK_LENGTH, returning cipherText instead");
|
||||
return cipherText;
|
||||
}
|
||||
else {
|
||||
@@ -59,7 +58,7 @@ function decrypt(key, cipherText, ivLength = 13) {
|
||||
}
|
||||
}
|
||||
|
||||
function pad(data) {
|
||||
function pad(data: any) {
|
||||
if (data.length > 16) {
|
||||
data = data.slice(0, 16);
|
||||
}
|
||||
@@ -72,7 +71,7 @@ function pad(data) {
|
||||
return Buffer.from(data);
|
||||
}
|
||||
|
||||
function arraysIdentical(a, b) {
|
||||
function arraysIdentical(a: any, b: any) {
|
||||
let i = a.length;
|
||||
if (i !== b.length) return false;
|
||||
while (i--) {
|
||||
@@ -81,12 +80,12 @@ function arraysIdentical(a, b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function shaArray(content) {
|
||||
function shaArray(content: any) {
|
||||
// we use this as simple checksum and don't rely on its security so SHA-1 is good enough
|
||||
return crypto.createHash('sha1').update(content).digest();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
decrypt,
|
||||
decryptString
|
||||
};
|
||||
@@ -1,11 +1,11 @@
|
||||
const fs = require("fs");
|
||||
const sanitize = require("sanitize-filename");
|
||||
const sql = require('./sql.js');
|
||||
const decryptService = require('./decrypt.js');
|
||||
const dataKeyService = require('./data_key.js');
|
||||
const extensionService = require('./extension.js');
|
||||
import fs from 'fs';
|
||||
import sanitize from 'sanitize-filename';
|
||||
import sql from './sql.js';
|
||||
import decryptService from './decrypt.js';
|
||||
import dataKeyService from './data_key.js';
|
||||
import extensionService from './extension.js';
|
||||
|
||||
function dumpDocument(documentPath, targetPath, options) {
|
||||
function dumpDocument(documentPath: string, targetPath: string, options: { password: any; includeDeleted: any; }) {
|
||||
const stats = {
|
||||
succeeded: 0,
|
||||
failed: 0,
|
||||
@@ -19,14 +19,14 @@ function dumpDocument(documentPath, targetPath, options) {
|
||||
|
||||
const dataKey = dataKeyService.getDataKey(options.password);
|
||||
|
||||
const existingPaths = {};
|
||||
const noteIdToPath = {};
|
||||
const existingPaths: Record<string, any> = {};
|
||||
const noteIdToPath: Record<string, any> = {};
|
||||
|
||||
dumpNote(targetPath, 'root');
|
||||
|
||||
printDumpResults(stats, options);
|
||||
|
||||
function dumpNote(targetPath, noteId) {
|
||||
function dumpNote(targetPath: any, noteId: any) {
|
||||
console.log(`Reading note '${noteId}'`);
|
||||
|
||||
let childTargetPath, noteRow, fileNameWithPath;
|
||||
@@ -94,7 +94,7 @@ function dumpDocument(documentPath, targetPath, options) {
|
||||
|
||||
noteIdToPath[noteId] = childTargetPath;
|
||||
}
|
||||
catch (e) {
|
||||
catch (e: any) {
|
||||
console.error(`DUMPERROR: Writing '${noteId}' failed with error '${e.message}':\n${e.stack}`);
|
||||
|
||||
stats.failed++;
|
||||
@@ -108,9 +108,9 @@ function dumpDocument(documentPath, targetPath, options) {
|
||||
}
|
||||
|
||||
try {
|
||||
fs.mkdirSync(childTargetPath, { recursive: true });
|
||||
fs.mkdirSync(childTargetPath as string, { recursive: true });
|
||||
}
|
||||
catch (e) {
|
||||
catch (e: any) {
|
||||
console.error(`DUMPERROR: Creating directory ${childTargetPath} failed with error '${e.message}'`);
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ function dumpDocument(documentPath, targetPath, options) {
|
||||
}
|
||||
}
|
||||
|
||||
function printDumpResults(stats, options) {
|
||||
function printDumpResults(stats: any, options: any) {
|
||||
console.log('\n----------------------- STATS -----------------------');
|
||||
console.log('Successfully dumpted notes: ', stats.succeeded.toString().padStart(5, ' '));
|
||||
console.log('Protected notes: ', stats.protected.toString().padStart(5, ' '), options.password ? '' : '(skipped)');
|
||||
@@ -134,7 +134,7 @@ function printDumpResults(stats, options) {
|
||||
}
|
||||
}
|
||||
|
||||
function isContentEmpty(content) {
|
||||
function isContentEmpty(content: any) {
|
||||
if (!content) {
|
||||
return true;
|
||||
}
|
||||
@@ -150,7 +150,7 @@ function isContentEmpty(content) {
|
||||
}
|
||||
}
|
||||
|
||||
function validatePaths(documentPath, targetPath) {
|
||||
function validatePaths(documentPath: string, targetPath: string) {
|
||||
if (!fs.existsSync(documentPath)) {
|
||||
console.error(`Path to document '${documentPath}' has not been found. Run with --help to see usage.`);
|
||||
process.exit(1);
|
||||
@@ -166,6 +166,6 @@ function validatePaths(documentPath, targetPath) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
dumpDocument
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
const path = require("path");
|
||||
const mimeTypes = require("mime-types");
|
||||
import path from "path";
|
||||
import mimeTypes from "mime-types";
|
||||
|
||||
function getFileName(note, childTargetPath, safeTitle) {
|
||||
function getFileName(note: any, childTargetPath: string, safeTitle: string) {
|
||||
let existingExtension = path.extname(safeTitle).toLowerCase();
|
||||
let newExtension;
|
||||
|
||||
@@ -29,6 +29,6 @@ function getFileName(note, childTargetPath, safeTitle) {
|
||||
return fileNameWithPath;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
getFileName
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
const Database = require("better-sqlite3");
|
||||
let dbConnection;
|
||||
|
||||
const openDatabase = (documentPath) => { dbConnection = new Database(documentPath, { readonly: true }) };
|
||||
|
||||
const getRow = (query, params = []) => dbConnection.prepare(query).get(params);
|
||||
const getRows = (query, params = []) => dbConnection.prepare(query).all(params);
|
||||
const getValue = (query, params = []) => dbConnection.prepare(query).pluck().get(params);
|
||||
const getColumn = (query, params = []) => dbConnection.prepare(query).pluck().all(params);
|
||||
|
||||
module.exports = {
|
||||
openDatabase,
|
||||
getRow,
|
||||
getRows,
|
||||
getValue,
|
||||
getColumn
|
||||
};
|
||||
18
dump-db/inc/sql.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import Database, { Database as DatabaseType } from "better-sqlite3";
|
||||
|
||||
let dbConnection: DatabaseType;
|
||||
|
||||
const openDatabase = (documentPath: string) => { dbConnection = new Database(documentPath, { readonly: true }) };
|
||||
|
||||
const getRow = (query: string, params: string[] = []): Record<string, any> => dbConnection.prepare(query).get(params) as Record<string, any>;
|
||||
const getRows = (query: string, params = []) => dbConnection.prepare(query).all(params);
|
||||
const getValue = (query: string, params: string[] = []) => dbConnection.prepare(query).pluck().get(params);
|
||||
const getColumn = (query: string, params: string[] = []) => dbConnection.prepare(query).pluck().all(params);
|
||||
|
||||
export default {
|
||||
openDatabase,
|
||||
getRow,
|
||||
getRows,
|
||||
getValue,
|
||||
getColumn
|
||||
};
|
||||
1513
dump-db/package-lock.json
generated
@@ -2,24 +2,30 @@
|
||||
"name": "dump-db",
|
||||
"version": "1.0.0",
|
||||
"description": "Standalone tool to dump contents of Trilium document.db file into a directory tree of notes",
|
||||
"main": "dump-db.js",
|
||||
"main": "dump-db.ts",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/zadam/trilium.git"
|
||||
"url": "git+https://github.com/TriliumNext/Notes.git"
|
||||
},
|
||||
"author": "zadam",
|
||||
"author": "TriliumNext",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/zadam/trilium/issues"
|
||||
"url": "https://github.com/TriliumNext/Notes/issues"
|
||||
},
|
||||
"homepage": "https://github.com/zadam/trilium/dump-db#readme",
|
||||
"homepage": "https://github.com/TriliumNext/Notes/blob/master/dump-db/README.md",
|
||||
"dependencies": {
|
||||
"better-sqlite3": "7.5.0",
|
||||
"mime-types": "2.1.34",
|
||||
"sanitize-filename": "1.6.3",
|
||||
"yargs": "17.3.1"
|
||||
"better-sqlite3": "^11.1.2",
|
||||
"esrun": "^3.2.26",
|
||||
"mime-types": "^2.1.34",
|
||||
"sanitize-filename": "^1.6.3",
|
||||
"yargs": "^17.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/better-sqlite3": "^7.6.11",
|
||||
"@types/mime-types": "^2.1.4",
|
||||
"@types/yargs": "^17.0.33"
|
||||
}
|
||||
}
|
||||
|
||||
10
dump-db/tsconfig.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"target": "ES6",
|
||||
"strict": true
|
||||
}
|
||||
}
|
||||
4
electron-main.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { initializeTranslations } from "./src/services/i18n.js";
|
||||
|
||||
await initializeTranslations();
|
||||
await import("./electron.js")
|
||||
@@ -70,4 +70,4 @@ electron.app.on("will-quit", () => {
|
||||
// this is to disable electron warning spam in the dev console (local development only)
|
||||
process.env["ELECTRON_DISABLE_SECURITY_WARNINGS"] = "true";
|
||||
|
||||
await import('./src/www.js');
|
||||
await import('./src/main.js');
|
||||
|
||||
@@ -1,18 +1,68 @@
|
||||
const path = require('path');
|
||||
const fs = require('fs-extra');
|
||||
|
||||
const APP_NAME = "TriliumNext Notes";
|
||||
|
||||
module.exports = {
|
||||
packagerConfig: {
|
||||
executableName: "trilium",
|
||||
name: APP_NAME,
|
||||
overwrite: true,
|
||||
asar: true,
|
||||
// icon will break once we add .dmg support, since the .ico & .icns have to be in same dir (see https://www.electronforge.io/guides/create-and-add-icons#windows-and-macos)
|
||||
icon: "./images/app-icons/win/icon"
|
||||
icon: "./images/app-icons/icon",
|
||||
extraResource: getExtraResourcesForPlatform(),
|
||||
afterComplete: [(buildPath, _electronVersion, platform, _arch, callback) => {
|
||||
const extraResources = getExtraResourcesForPlatform();
|
||||
for (const resource of extraResources) {
|
||||
let sourcePath;
|
||||
if (platform === 'darwin') {
|
||||
sourcePath = path.join(buildPath, `${APP_NAME}.app`, 'Contents', 'Resources', path.basename(resource));
|
||||
} else {
|
||||
sourcePath = path.join(buildPath, 'resources', path.basename(resource));
|
||||
}
|
||||
const destPath = path.join(buildPath, path.basename(resource));
|
||||
|
||||
// Copy files from resources folder to root
|
||||
fs.move(sourcePath, destPath)
|
||||
.then(() => callback())
|
||||
.catch(err => callback(err));
|
||||
}
|
||||
}]
|
||||
},
|
||||
rebuildConfig: {
|
||||
force: true
|
||||
},
|
||||
rebuildConfig: {},
|
||||
makers: [
|
||||
{
|
||||
name: '@electron-forge/maker-deb',
|
||||
config: {
|
||||
options: {
|
||||
icon: "./images/app-icons/png/128x128.png",
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '@electron-forge/maker-squirrel',
|
||||
config: {
|
||||
iconUrl: "https://raw.githubusercontent.com/TriliumNext/Notes/develop/images/app-icons/win/icon.ico",
|
||||
setupIcon: "./images/app-icons/win/icon.ico",
|
||||
iconUrl: "https://raw.githubusercontent.com/TriliumNext/Notes/develop/images/app-icons/icon.ico",
|
||||
setupIcon: "./images/app-icons/icon.ico",
|
||||
loadingGif: "./images/app-icons/win/setup-banner.gif"
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '@electron-forge/maker-dmg',
|
||||
config: {
|
||||
icon: "./images/app-icons/icon.icns",
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '@electron-forge/maker-zip',
|
||||
config: {
|
||||
options: {
|
||||
iconUrl: "https://raw.githubusercontent.com/TriliumNext/Notes/develop/images/app-icons/icon.ico",
|
||||
icon: "./images/app-icons/icon.ico",
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
plugins: [
|
||||
@@ -22,3 +72,27 @@ module.exports = {
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
function getExtraResourcesForPlatform() {
|
||||
let resources = ['dump-db/', './bin/tpl/anonymize-database.sql']
|
||||
const scripts = ['trilium-portable', 'trilium-safe-mode', 'trilium-no-cert-check']
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
for (const script of scripts) {
|
||||
resources.push(`./bin/tpl/${script}.bat`)
|
||||
}
|
||||
break;
|
||||
case 'darwin':
|
||||
break;
|
||||
case 'linux':
|
||||
for (const script of scripts) {
|
||||
resources.push(`./bin/tpl/${script}.sh`)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return resources;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 112 KiB |
BIN
images/app-icons/png/1000x1000.png
Normal file
|
After Width: | Height: | Size: 93 KiB |
BIN
images/app-icons/png/1024x1024.png
Normal file
|
After Width: | Height: | Size: 107 KiB |
BIN
images/app-icons/png/16x16.png
Normal file
|
After Width: | Height: | Size: 626 B |
BIN
images/app-icons/png/32x32.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
images/app-icons/png/512x512.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
17
integration-tests/auth.setup.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { test as setup, expect } from '@playwright/test';
|
||||
|
||||
const authFile = 'playwright/.auth/user.json';
|
||||
|
||||
const ROOT_URL = "http://localhost:8082";
|
||||
const LOGIN_PASSWORD = "demo1234";
|
||||
|
||||
// Reference: https://playwright.dev/docs/auth#basic-shared-account-in-all-tests
|
||||
|
||||
setup("authenticate", async ({ page }) => {
|
||||
await page.goto(ROOT_URL);
|
||||
await expect(page).toHaveURL(`${ROOT_URL}/login`);
|
||||
|
||||
await page.getByRole("textbox", { name: "Password" }).fill(LOGIN_PASSWORD);
|
||||
await page.getByRole("button", { name: "Login"}).click();
|
||||
await page.context().storageState({ path: authFile });
|
||||
});
|
||||
BIN
integration-tests/db/document.db
Normal file
9
integration-tests/duplicate.spec.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test("Can duplicate note with broken links", async ({ page }) => {
|
||||
await page.goto(`http://localhost:8082/#2VammGGdG6Ie`);
|
||||
await page.locator('.tree-wrapper .fancytree-active').getByText('Note map').click({ button: 'right' });
|
||||
await page.getByText('Duplicate subtree').click();
|
||||
await expect(page.locator(".toast-body")).toBeHidden();
|
||||
await expect(page.locator('.tree-wrapper').getByText('Note map (dup)')).toBeVisible();
|
||||
});
|
||||
18
integration-tests/example.disabled.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('has title', async ({ page }) => {
|
||||
await page.goto('https://playwright.dev/');
|
||||
|
||||
// Expect a title "to contain" a substring.
|
||||
await expect(page).toHaveTitle(/Playwright/);
|
||||
});
|
||||
|
||||
test('get started link', async ({ page }) => {
|
||||
await page.goto('https://playwright.dev/');
|
||||
|
||||
// Click the get started link.
|
||||
await page.getByRole('link', { name: 'Get started' }).click();
|
||||
|
||||
// Expects page to have a heading with the name of Installation.
|
||||
await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible();
|
||||
});
|
||||
23
integration-tests/help.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import test, { expect } from "@playwright/test";
|
||||
|
||||
test('Help popup', async ({ page }) => {
|
||||
await page.goto('http://localhost:8082');
|
||||
await page.getByText('Trilium Integration Test DB').click();
|
||||
|
||||
await page.locator('body').press('F1');
|
||||
await page.getByRole('link', { name: 'online↗' }).click();
|
||||
expect((await page.waitForEvent('popup')).url()).toBe("https://triliumnext.github.io/Docs/")
|
||||
});
|
||||
|
||||
test('Complete help in search', async ({ page }) => {
|
||||
await page.goto('http://localhost:8082');
|
||||
|
||||
// Clear all tabs
|
||||
await page.locator('.note-tab:first-of-type').locator("div").nth(1).click({ button: 'right' });
|
||||
await page.getByText('Close all tabs').click();
|
||||
|
||||
await page.locator('#launcher-container').getByRole('button', { name: '' }).first().click();
|
||||
await page.getByRole('cell', { name: ' ' }).locator('span').first().click();
|
||||
await page.getByRole('button', { name: 'complete help on search syntax' }).click();
|
||||
expect((await page.waitForEvent('popup')).url()).toBe("https://triliumnext.github.io/Docs/Wiki/search.html");
|
||||
});
|
||||
43
integration-tests/i18n.spec.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import test, { expect } from "@playwright/test";
|
||||
|
||||
test("User can change language from settings", async ({ page }) => {
|
||||
await page.goto('http://localhost:8082');
|
||||
|
||||
// Clear all tabs
|
||||
await page.locator('.note-tab:first-of-type').locator("div").nth(1).click({ button: 'right' });
|
||||
await page.getByText('Close all tabs').click();
|
||||
|
||||
// Go to options -> Appearance
|
||||
await page.locator('#launcher-pane div').filter({ hasText: 'Options Open New Window' }).getByRole('button').click();
|
||||
await page.locator('#launcher-pane').getByText('Options').click();
|
||||
await page.locator('#center-pane').getByText('Appearance').click();
|
||||
|
||||
// Check that the default value (English) is set.
|
||||
await expect(page.locator('#center-pane')).toContainText('Theme');
|
||||
const languageCombobox = await page.getByRole('combobox').first();
|
||||
await expect(languageCombobox).toHaveValue("en");
|
||||
|
||||
// Select Chinese and ensure the translation is set.
|
||||
languageCombobox.selectOption("cn");
|
||||
await expect(page.locator('#center-pane')).toContainText('主题');
|
||||
|
||||
// Select English again.
|
||||
languageCombobox.selectOption("en");
|
||||
});
|
||||
|
||||
test("Restores language on start-up on desktop", async ({ page, context }) => {
|
||||
await page.goto('http://localhost:8082');
|
||||
await expect(page.locator('#launcher-pane').first()).toContainText("Open New Window");
|
||||
});
|
||||
|
||||
test("Restores language on start-up on mobile", async ({ page, context }) => {
|
||||
await context.addCookies([
|
||||
{
|
||||
url: "http://localhost:8082",
|
||||
name: "trilium-device",
|
||||
value: "mobile"
|
||||
}
|
||||
]);
|
||||
await page.goto('http://localhost:8082');
|
||||
await expect(page.locator('#launcher-pane div').first()).toContainText("Open New Window");
|
||||
});
|
||||
18
integration-tests/katex.disabled.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
const ROOT_URL = "http://localhost:8080";
|
||||
const LOGIN_PASSWORD = "eliandoran";
|
||||
|
||||
test("Can insert equations", async ({ page }) => {
|
||||
await page.setDefaultTimeout(60_000);
|
||||
await page.setDefaultNavigationTimeout(60_000);
|
||||
|
||||
// Create a new note
|
||||
// await page.locator("button.button-widget.bx-file-blank")
|
||||
// .click();
|
||||
|
||||
const activeNote = page.locator(".component.note-split:visible");
|
||||
const noteContent = activeNote
|
||||
.locator(".note-detail-editable-text-editor")
|
||||
await noteContent.press("Ctrl+M");
|
||||
});
|
||||
21
integration-tests/settings.spec.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import test, { expect } from "@playwright/test";
|
||||
|
||||
test("Native Title Bar not displayed on web", async ({ page }) => {
|
||||
await page.goto('http://localhost:8082/#root/_hidden/_options/_optionsAppearance');
|
||||
await expect(page.getByRole('heading', { name: 'Theme' })).toBeVisible();
|
||||
await expect(page.getByRole('heading', { name: 'Native Title Bar (requires' })).toBeHidden();
|
||||
});
|
||||
|
||||
test("Tray settings not displayed on web", async ({ page }) => {
|
||||
await page.goto('http://localhost:8082/#root/_hidden/_options/_optionsOther');
|
||||
await expect(page.getByRole('heading', { name: 'Note Erasure Timeout' })).toBeVisible();
|
||||
await expect(page.getByRole('heading', { name: 'Tray' })).toBeHidden();
|
||||
});
|
||||
|
||||
test("Spellcheck settings not displayed on web", async ({ page }) => {
|
||||
await page.goto('http://localhost:8082/#root/_hidden/_options/_optionsSpellcheck');
|
||||
await expect(page.getByRole('heading', { name: 'Spell Check' })).toBeVisible();
|
||||
await expect(page.getByRole('heading', { name: 'Tray' })).toBeHidden();
|
||||
await expect(page.getByText('These options apply only for desktop builds')).toBeVisible();
|
||||
await expect(page.getByText('Enable spellcheck')).toBeHidden();
|
||||
});
|
||||
18
integration-tests/tree.spec.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import test, { expect } from "@playwright/test";
|
||||
|
||||
test("Renders on desktop", async ({ page, context }) => {
|
||||
await page.goto('http://localhost:8082');
|
||||
await expect(page.locator('.tree')).toContainText('Trilium Integration Test');
|
||||
});
|
||||
|
||||
test("Renders on mobile", async ({ page, context }) => {
|
||||
await context.addCookies([
|
||||
{
|
||||
url: "http://localhost:8082",
|
||||
name: "trilium-device",
|
||||
value: "mobile"
|
||||
}
|
||||
]);
|
||||
await page.goto('http://localhost:8082');
|
||||
await expect(page.locator('.tree')).toContainText('Trilium Integration Test');
|
||||
});
|
||||
12
integration-tests/update_check.spec.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
const expectedVersion = "0.90.3";
|
||||
|
||||
test("Displays update badge when there is a version available", async ({ page }) => {
|
||||
await page.goto("http://localhost:8080");
|
||||
await page.getByRole('button', { name: '' }).click();
|
||||
await page.getByText(`Version ${expectedVersion} is available,`).click();
|
||||
|
||||
const page1 = await page.waitForEvent('popup');
|
||||
expect(page1.url()).toBe(`https://github.com/TriliumNext/Notes/releases/tag/v${expectedVersion}`);
|
||||
});
|
||||
7
libraries/autocomplete.jquery.min.js
vendored
7
libraries/bootstrap/css/bootstrap.min.css
vendored
@@ -4,6 +4,10 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ck-content li p {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
/*
|
||||
* CKEditor 5 (v41.0.0) content styles.
|
||||
* Generated on Fri, 26 Jan 2024 10:23:49 GMT.
|
||||
|
||||
2
libraries/ckeditor/ckeditor.js
vendored
@@ -1,78 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
CodeMirror.defineOption("placeholder", "", function(cm, val, old) {
|
||||
var prev = old && old != CodeMirror.Init;
|
||||
if (val && !prev) {
|
||||
cm.on("blur", onBlur);
|
||||
cm.on("change", onChange);
|
||||
cm.on("swapDoc", onChange);
|
||||
CodeMirror.on(cm.getInputField(), "compositionupdate", cm.state.placeholderCompose = function() { onComposition(cm) })
|
||||
onChange(cm);
|
||||
} else if (!val && prev) {
|
||||
cm.off("blur", onBlur);
|
||||
cm.off("change", onChange);
|
||||
cm.off("swapDoc", onChange);
|
||||
CodeMirror.off(cm.getInputField(), "compositionupdate", cm.state.placeholderCompose)
|
||||
clearPlaceholder(cm);
|
||||
var wrapper = cm.getWrapperElement();
|
||||
wrapper.className = wrapper.className.replace(" CodeMirror-empty", "");
|
||||
}
|
||||
|
||||
if (val && !cm.hasFocus()) onBlur(cm);
|
||||
});
|
||||
|
||||
function clearPlaceholder(cm) {
|
||||
if (cm.state.placeholder) {
|
||||
cm.state.placeholder.parentNode.removeChild(cm.state.placeholder);
|
||||
cm.state.placeholder = null;
|
||||
}
|
||||
}
|
||||
function setPlaceholder(cm) {
|
||||
clearPlaceholder(cm);
|
||||
var elt = cm.state.placeholder = document.createElement("pre");
|
||||
elt.style.cssText = "height: 0; overflow: visible";
|
||||
elt.style.direction = cm.getOption("direction");
|
||||
elt.className = "CodeMirror-placeholder CodeMirror-line-like";
|
||||
var placeHolder = cm.getOption("placeholder")
|
||||
if (typeof placeHolder == "string") placeHolder = document.createTextNode(placeHolder)
|
||||
elt.appendChild(placeHolder)
|
||||
cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild);
|
||||
}
|
||||
|
||||
function onComposition(cm) {
|
||||
setTimeout(function() {
|
||||
var empty = false
|
||||
if (cm.lineCount() == 1) {
|
||||
var input = cm.getInputField()
|
||||
empty = input.nodeName == "TEXTAREA" ? !cm.getLine(0).length
|
||||
: !/[^\u200b]/.test(input.querySelector(".CodeMirror-line").textContent)
|
||||
}
|
||||
if (empty) setPlaceholder(cm)
|
||||
else clearPlaceholder(cm)
|
||||
}, 20)
|
||||
}
|
||||
|
||||
function onBlur(cm) {
|
||||
if (isEmpty(cm)) setPlaceholder(cm);
|
||||
}
|
||||
function onChange(cm) {
|
||||
var wrapper = cm.getWrapperElement(), empty = isEmpty(cm);
|
||||
wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : "");
|
||||
|
||||
if (empty) setPlaceholder(cm);
|
||||
else clearPlaceholder(cm);
|
||||
}
|
||||
|
||||
function isEmpty(cm) {
|
||||
return (cm.lineCount() === 1) && (cm.getLine(0) === "");
|
||||
}
|
||||
});
|
||||
160
libraries/codemirror/addon/edit/matchbrackets.js
vendored
@@ -1,160 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
var ie_lt8 = /MSIE \d/.test(navigator.userAgent) &&
|
||||
(document.documentMode == null || document.documentMode < 8);
|
||||
|
||||
var Pos = CodeMirror.Pos;
|
||||
|
||||
var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<", "<": ">>", ">": "<<"};
|
||||
|
||||
function bracketRegex(config) {
|
||||
return config && config.bracketRegex || /[(){}[\]]/
|
||||
}
|
||||
|
||||
function findMatchingBracket(cm, where, config) {
|
||||
var line = cm.getLineHandle(where.line), pos = where.ch - 1;
|
||||
var afterCursor = config && config.afterCursor
|
||||
if (afterCursor == null)
|
||||
afterCursor = /(^| )cm-fat-cursor($| )/.test(cm.getWrapperElement().className)
|
||||
var re = bracketRegex(config)
|
||||
|
||||
// A cursor is defined as between two characters, but in in vim command mode
|
||||
// (i.e. not insert mode), the cursor is visually represented as a
|
||||
// highlighted box on top of the 2nd character. Otherwise, we allow matches
|
||||
// from before or after the cursor.
|
||||
var match = (!afterCursor && pos >= 0 && re.test(line.text.charAt(pos)) && matching[line.text.charAt(pos)]) ||
|
||||
re.test(line.text.charAt(pos + 1)) && matching[line.text.charAt(++pos)];
|
||||
if (!match) return null;
|
||||
var dir = match.charAt(1) == ">" ? 1 : -1;
|
||||
if (config && config.strict && (dir > 0) != (pos == where.ch)) return null;
|
||||
var style = cm.getTokenTypeAt(Pos(where.line, pos + 1));
|
||||
|
||||
var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style, config);
|
||||
if (found == null) return null;
|
||||
return {from: Pos(where.line, pos), to: found && found.pos,
|
||||
match: found && found.ch == match.charAt(0), forward: dir > 0};
|
||||
}
|
||||
|
||||
// bracketRegex is used to specify which type of bracket to scan
|
||||
// should be a regexp, e.g. /[[\]]/
|
||||
//
|
||||
// Note: If "where" is on an open bracket, then this bracket is ignored.
|
||||
//
|
||||
// Returns false when no bracket was found, null when it reached
|
||||
// maxScanLines and gave up
|
||||
function scanForBracket(cm, where, dir, style, config) {
|
||||
var maxScanLen = (config && config.maxScanLineLength) || 10000;
|
||||
var maxScanLines = (config && config.maxScanLines) || 1000;
|
||||
|
||||
var stack = [];
|
||||
var re = bracketRegex(config)
|
||||
var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1)
|
||||
: Math.max(cm.firstLine() - 1, where.line - maxScanLines);
|
||||
for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) {
|
||||
var line = cm.getLine(lineNo);
|
||||
if (!line) continue;
|
||||
var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1;
|
||||
if (line.length > maxScanLen) continue;
|
||||
if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0);
|
||||
for (; pos != end; pos += dir) {
|
||||
var ch = line.charAt(pos);
|
||||
if (re.test(ch) && (style === undefined ||
|
||||
(cm.getTokenTypeAt(Pos(lineNo, pos + 1)) || "") == (style || ""))) {
|
||||
var match = matching[ch];
|
||||
if (match && (match.charAt(1) == ">") == (dir > 0)) stack.push(ch);
|
||||
else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch};
|
||||
else stack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null;
|
||||
}
|
||||
|
||||
function matchBrackets(cm, autoclear, config) {
|
||||
// Disable brace matching in long lines, since it'll cause hugely slow updates
|
||||
var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000,
|
||||
highlightNonMatching = config && config.highlightNonMatching;
|
||||
var marks = [], ranges = cm.listSelections();
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, config);
|
||||
if (match && (match.match || highlightNonMatching !== false) && cm.getLine(match.from.line).length <= maxHighlightLen) {
|
||||
var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
|
||||
marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style}));
|
||||
if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen)
|
||||
marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style}));
|
||||
}
|
||||
}
|
||||
|
||||
if (marks.length) {
|
||||
// Kludge to work around the IE bug from issue #1193, where text
|
||||
// input stops going to the textarea whenever this fires.
|
||||
if (ie_lt8 && cm.state.focused) cm.focus();
|
||||
|
||||
var clear = function() {
|
||||
cm.operation(function() {
|
||||
for (var i = 0; i < marks.length; i++) marks[i].clear();
|
||||
});
|
||||
};
|
||||
if (autoclear) setTimeout(clear, 800);
|
||||
else return clear;
|
||||
}
|
||||
}
|
||||
|
||||
function doMatchBrackets(cm) {
|
||||
cm.operation(function() {
|
||||
if (cm.state.matchBrackets.currentlyHighlighted) {
|
||||
cm.state.matchBrackets.currentlyHighlighted();
|
||||
cm.state.matchBrackets.currentlyHighlighted = null;
|
||||
}
|
||||
cm.state.matchBrackets.currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);
|
||||
});
|
||||
}
|
||||
|
||||
function clearHighlighted(cm) {
|
||||
if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) {
|
||||
cm.state.matchBrackets.currentlyHighlighted();
|
||||
cm.state.matchBrackets.currentlyHighlighted = null;
|
||||
}
|
||||
}
|
||||
|
||||
CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init) {
|
||||
cm.off("cursorActivity", doMatchBrackets);
|
||||
cm.off("focus", doMatchBrackets)
|
||||
cm.off("blur", clearHighlighted)
|
||||
clearHighlighted(cm);
|
||||
}
|
||||
if (val) {
|
||||
cm.state.matchBrackets = typeof val == "object" ? val : {};
|
||||
cm.on("cursorActivity", doMatchBrackets);
|
||||
cm.on("focus", doMatchBrackets)
|
||||
cm.on("blur", clearHighlighted)
|
||||
}
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
|
||||
CodeMirror.defineExtension("findMatchingBracket", function(pos, config, oldConfig){
|
||||
// Backwards-compatibility kludge
|
||||
if (oldConfig || typeof config == "boolean") {
|
||||
if (!oldConfig) {
|
||||
config = config ? {strict: true} : null
|
||||
} else {
|
||||
oldConfig.strict = config
|
||||
config = oldConfig
|
||||
}
|
||||
}
|
||||
return findMatchingBracket(this, pos, config)
|
||||
});
|
||||
CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){
|
||||
return scanForBracket(this, pos, dir, style, config);
|
||||
});
|
||||
});
|
||||
66
libraries/codemirror/addon/edit/matchtags.js
vendored
@@ -1,66 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"), require("../fold/xml-fold"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "../fold/xml-fold"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineOption("matchTags", false, function(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init) {
|
||||
cm.off("cursorActivity", doMatchTags);
|
||||
cm.off("viewportChange", maybeUpdateMatch);
|
||||
clear(cm);
|
||||
}
|
||||
if (val) {
|
||||
cm.state.matchBothTags = typeof val == "object" && val.bothTags;
|
||||
cm.on("cursorActivity", doMatchTags);
|
||||
cm.on("viewportChange", maybeUpdateMatch);
|
||||
doMatchTags(cm);
|
||||
}
|
||||
});
|
||||
|
||||
function clear(cm) {
|
||||
if (cm.state.tagHit) cm.state.tagHit.clear();
|
||||
if (cm.state.tagOther) cm.state.tagOther.clear();
|
||||
cm.state.tagHit = cm.state.tagOther = null;
|
||||
}
|
||||
|
||||
function doMatchTags(cm) {
|
||||
cm.state.failedTagMatch = false;
|
||||
cm.operation(function() {
|
||||
clear(cm);
|
||||
if (cm.somethingSelected()) return;
|
||||
var cur = cm.getCursor(), range = cm.getViewport();
|
||||
range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to);
|
||||
var match = CodeMirror.findMatchingTag(cm, cur, range);
|
||||
if (!match) return;
|
||||
if (cm.state.matchBothTags) {
|
||||
var hit = match.at == "open" ? match.open : match.close;
|
||||
if (hit) cm.state.tagHit = cm.markText(hit.from, hit.to, {className: "CodeMirror-matchingtag"});
|
||||
}
|
||||
var other = match.at == "close" ? match.open : match.close;
|
||||
if (other)
|
||||
cm.state.tagOther = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"});
|
||||
else
|
||||
cm.state.failedTagMatch = true;
|
||||
});
|
||||
}
|
||||
|
||||
function maybeUpdateMatch(cm) {
|
||||
if (cm.state.failedTagMatch) doMatchTags(cm);
|
||||
}
|
||||
|
||||
CodeMirror.commands.toMatchingTag = function(cm) {
|
||||
var found = CodeMirror.findMatchingTag(cm, cm.getCursor());
|
||||
if (found) {
|
||||
var other = found.at == "close" ? found.open : found.close;
|
||||
if (other) cm.extendSelection(other.to, other.from);
|
||||
}
|
||||
};
|
||||
});
|
||||
184
libraries/codemirror/addon/fold/xml-fold.js
vendored
@@ -1,184 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var Pos = CodeMirror.Pos;
|
||||
function cmp(a, b) { return a.line - b.line || a.ch - b.ch; }
|
||||
|
||||
var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
|
||||
var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
|
||||
var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g");
|
||||
|
||||
function Iter(cm, line, ch, range) {
|
||||
this.line = line; this.ch = ch;
|
||||
this.cm = cm; this.text = cm.getLine(line);
|
||||
this.min = range ? Math.max(range.from, cm.firstLine()) : cm.firstLine();
|
||||
this.max = range ? Math.min(range.to - 1, cm.lastLine()) : cm.lastLine();
|
||||
}
|
||||
|
||||
function tagAt(iter, ch) {
|
||||
var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch));
|
||||
return type && /\btag\b/.test(type);
|
||||
}
|
||||
|
||||
function nextLine(iter) {
|
||||
if (iter.line >= iter.max) return;
|
||||
iter.ch = 0;
|
||||
iter.text = iter.cm.getLine(++iter.line);
|
||||
return true;
|
||||
}
|
||||
function prevLine(iter) {
|
||||
if (iter.line <= iter.min) return;
|
||||
iter.text = iter.cm.getLine(--iter.line);
|
||||
iter.ch = iter.text.length;
|
||||
return true;
|
||||
}
|
||||
|
||||
function toTagEnd(iter) {
|
||||
for (;;) {
|
||||
var gt = iter.text.indexOf(">", iter.ch);
|
||||
if (gt == -1) { if (nextLine(iter)) continue; else return; }
|
||||
if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; }
|
||||
var lastSlash = iter.text.lastIndexOf("/", gt);
|
||||
var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
|
||||
iter.ch = gt + 1;
|
||||
return selfClose ? "selfClose" : "regular";
|
||||
}
|
||||
}
|
||||
function toTagStart(iter) {
|
||||
for (;;) {
|
||||
var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1;
|
||||
if (lt == -1) { if (prevLine(iter)) continue; else return; }
|
||||
if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; }
|
||||
xmlTagStart.lastIndex = lt;
|
||||
iter.ch = lt;
|
||||
var match = xmlTagStart.exec(iter.text);
|
||||
if (match && match.index == lt) return match;
|
||||
}
|
||||
}
|
||||
|
||||
function toNextTag(iter) {
|
||||
for (;;) {
|
||||
xmlTagStart.lastIndex = iter.ch;
|
||||
var found = xmlTagStart.exec(iter.text);
|
||||
if (!found) { if (nextLine(iter)) continue; else return; }
|
||||
if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; }
|
||||
iter.ch = found.index + found[0].length;
|
||||
return found;
|
||||
}
|
||||
}
|
||||
function toPrevTag(iter) {
|
||||
for (;;) {
|
||||
var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1;
|
||||
if (gt == -1) { if (prevLine(iter)) continue; else return; }
|
||||
if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; }
|
||||
var lastSlash = iter.text.lastIndexOf("/", gt);
|
||||
var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
|
||||
iter.ch = gt + 1;
|
||||
return selfClose ? "selfClose" : "regular";
|
||||
}
|
||||
}
|
||||
|
||||
function findMatchingClose(iter, tag) {
|
||||
var stack = [];
|
||||
for (;;) {
|
||||
var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0);
|
||||
if (!next || !(end = toTagEnd(iter))) return;
|
||||
if (end == "selfClose") continue;
|
||||
if (next[1]) { // closing tag
|
||||
for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) {
|
||||
stack.length = i;
|
||||
break;
|
||||
}
|
||||
if (i < 0 && (!tag || tag == next[2])) return {
|
||||
tag: next[2],
|
||||
from: Pos(startLine, startCh),
|
||||
to: Pos(iter.line, iter.ch)
|
||||
};
|
||||
} else { // opening tag
|
||||
stack.push(next[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
function findMatchingOpen(iter, tag) {
|
||||
var stack = [];
|
||||
for (;;) {
|
||||
var prev = toPrevTag(iter);
|
||||
if (!prev) return;
|
||||
if (prev == "selfClose") { toTagStart(iter); continue; }
|
||||
var endLine = iter.line, endCh = iter.ch;
|
||||
var start = toTagStart(iter);
|
||||
if (!start) return;
|
||||
if (start[1]) { // closing tag
|
||||
stack.push(start[2]);
|
||||
} else { // opening tag
|
||||
for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) {
|
||||
stack.length = i;
|
||||
break;
|
||||
}
|
||||
if (i < 0 && (!tag || tag == start[2])) return {
|
||||
tag: start[2],
|
||||
from: Pos(iter.line, iter.ch),
|
||||
to: Pos(endLine, endCh)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CodeMirror.registerHelper("fold", "xml", function(cm, start) {
|
||||
var iter = new Iter(cm, start.line, 0);
|
||||
for (;;) {
|
||||
var openTag = toNextTag(iter)
|
||||
if (!openTag || iter.line != start.line) return
|
||||
var end = toTagEnd(iter)
|
||||
if (!end) return
|
||||
if (!openTag[1] && end != "selfClose") {
|
||||
var startPos = Pos(iter.line, iter.ch);
|
||||
var endPos = findMatchingClose(iter, openTag[2]);
|
||||
return endPos && cmp(endPos.from, startPos) > 0 ? {from: startPos, to: endPos.from} : null
|
||||
}
|
||||
}
|
||||
});
|
||||
CodeMirror.findMatchingTag = function(cm, pos, range) {
|
||||
var iter = new Iter(cm, pos.line, pos.ch, range);
|
||||
if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return;
|
||||
var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch);
|
||||
var start = end && toTagStart(iter);
|
||||
if (!end || !start || cmp(iter, pos) > 0) return;
|
||||
var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]};
|
||||
if (end == "selfClose") return {open: here, close: null, at: "open"};
|
||||
|
||||
if (start[1]) { // closing tag
|
||||
return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"};
|
||||
} else { // opening tag
|
||||
iter = new Iter(cm, to.line, to.ch, range);
|
||||
return {open: here, close: findMatchingClose(iter, start[2]), at: "open"};
|
||||
}
|
||||
};
|
||||
|
||||
CodeMirror.findEnclosingTag = function(cm, pos, range, tag) {
|
||||
var iter = new Iter(cm, pos.line, pos.ch, range);
|
||||
for (;;) {
|
||||
var open = findMatchingOpen(iter, tag);
|
||||
if (!open) break;
|
||||
var forward = new Iter(cm, pos.line, pos.ch, range);
|
||||
var close = findMatchingClose(forward, open.tag);
|
||||
if (close) return {open: open, close: close};
|
||||
}
|
||||
};
|
||||
|
||||
// Used by addon/edit/closetag.js
|
||||
CodeMirror.scanForClosingTag = function(cm, pos, name, end) {
|
||||
var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null);
|
||||
return findMatchingClose(iter, name);
|
||||
};
|
||||
});
|
||||
98
libraries/codemirror/addon/lint/eslint.js
vendored
@@ -1,98 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
async function validatorHtml(text, options) {
|
||||
const result = /<script[^>]*>([\s\S]+)<\/script>/ig.exec(text);
|
||||
|
||||
if (result !== null) {
|
||||
// preceding code is copied over but any (non-newline) character is replaced with space
|
||||
// this will preserve line numbers etc.
|
||||
const prefix = text.substr(0, result.index).replace(/./g, " ");
|
||||
|
||||
const js = prefix + result[1];
|
||||
|
||||
return await validatorJavaScript(js, options);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
async function validatorJavaScript(text, options) {
|
||||
if (glob.isMobile()
|
||||
|| glob.getActiveContextNote() == null
|
||||
|| glob.getActiveContextNote().mime === 'application/json') {
|
||||
// eslint doesn't seem to validate pure JSON well
|
||||
return [];
|
||||
}
|
||||
|
||||
await glob.requireLibrary(glob.ESLINT);
|
||||
|
||||
if (text.length > 20000) {
|
||||
console.log("Skipping linting because of large size: ", text.length);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
const errors = new eslint().verify(text, {
|
||||
root: true,
|
||||
parserOptions: {
|
||||
ecmaVersion: "latest"
|
||||
},
|
||||
extends: ['eslint:recommended', 'airbnb-base'],
|
||||
env: {
|
||||
'browser': true,
|
||||
'node': true
|
||||
},
|
||||
rules: {
|
||||
'import/no-unresolved': 'off',
|
||||
'func-names': 'off',
|
||||
'comma-dangle': ['warn'],
|
||||
'padded-blocks': 'off',
|
||||
'linebreak-style': 'off',
|
||||
'class-methods-use-this': 'off',
|
||||
'no-unused-vars': ['warn', { vars: 'local', args: 'after-used' }],
|
||||
'no-nested-ternary': 'off',
|
||||
'no-underscore-dangle': ['error', {'allow': ['_super', '_lookupFactory']}]
|
||||
},
|
||||
globals: {
|
||||
"api": "readonly"
|
||||
}
|
||||
});
|
||||
|
||||
const result = [];
|
||||
if (errors) {
|
||||
parseErrors(errors, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeMirror.registerHelper("lint", "javascript", validatorJavaScript);
|
||||
CodeMirror.registerHelper("lint", "html", validatorHtml);
|
||||
|
||||
function parseErrors(errors, output) {
|
||||
for (const error of errors) {
|
||||
const startLine = error.line - 1;
|
||||
const endLine = error.endLine !== undefined ? error.endLine - 1 : startLine;
|
||||
const startCol = error.column - 1;
|
||||
const endCol = error.endColumn !== undefined ? error.endColumn - 1 : startCol + 1;
|
||||
|
||||
output.push({
|
||||
message: error.message,
|
||||
severity: error.severity === 1 ? "warning" : "error",
|
||||
from: CodeMirror.Pos(startLine, startCol),
|
||||
to: CodeMirror.Pos(endLine, endCol)
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
79
libraries/codemirror/addon/lint/lint.css
vendored
@@ -1,79 +0,0 @@
|
||||
/* The lint marker gutter */
|
||||
.CodeMirror-lint-markers {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.CodeMirror-lint-tooltip {
|
||||
background-color: #ffd;
|
||||
border: 1px solid black;
|
||||
border-radius: 4px 4px 4px 4px;
|
||||
color: black;
|
||||
font-family: monospace;
|
||||
font-size: 10pt;
|
||||
overflow: hidden;
|
||||
padding: 2px 5px;
|
||||
position: fixed;
|
||||
white-space: pre;
|
||||
white-space: pre-wrap;
|
||||
z-index: 100;
|
||||
max-width: 600px;
|
||||
opacity: 0;
|
||||
transition: opacity .4s;
|
||||
-moz-transition: opacity .4s;
|
||||
-webkit-transition: opacity .4s;
|
||||
-o-transition: opacity .4s;
|
||||
-ms-transition: opacity .4s;
|
||||
}
|
||||
|
||||
.CodeMirror-lint-mark {
|
||||
background-position: left bottom;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
.CodeMirror-lint-mark-warning {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII=");
|
||||
}
|
||||
|
||||
.CodeMirror-lint-mark-error {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==");
|
||||
}
|
||||
|
||||
.CodeMirror-lint-marker {
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.CodeMirror-lint-message {
|
||||
padding-left: 18px;
|
||||
background-position: top left;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII=");
|
||||
}
|
||||
|
||||
.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII=");
|
||||
}
|
||||
|
||||
.CodeMirror-lint-marker-multiple {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right bottom;
|
||||
width: 100%; height: 100%;
|
||||
}
|
||||
|
||||
.CodeMirror-lint-line-error {
|
||||
background-color: rgba(183, 76, 81, 0.08);
|
||||
}
|
||||
|
||||
.CodeMirror-lint-line-warning {
|
||||
background-color: rgba(255, 211, 0, 0.1);
|
||||
}
|
||||
288
libraries/codemirror/addon/lint/lint.js
vendored
@@ -1,288 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
var GUTTER_ID = "CodeMirror-lint-markers";
|
||||
var LINT_LINE_ID = "CodeMirror-lint-line-";
|
||||
|
||||
function showTooltip(cm, e, content) {
|
||||
var tt = document.createElement("div");
|
||||
tt.className = "CodeMirror-lint-tooltip cm-s-" + cm.options.theme;
|
||||
tt.appendChild(content.cloneNode(true));
|
||||
if (cm.state.lint.options.selfContain)
|
||||
cm.getWrapperElement().appendChild(tt);
|
||||
else
|
||||
document.body.appendChild(tt);
|
||||
|
||||
function position(e) {
|
||||
if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position);
|
||||
var top = Math.max(0, e.clientY - tt.offsetHeight - 5);
|
||||
var left = Math.max(0, Math.min(e.clientX + 5, tt.ownerDocument.defaultView.innerWidth - tt.offsetWidth));
|
||||
tt.style.top = top + "px"
|
||||
tt.style.left = left + "px";
|
||||
}
|
||||
CodeMirror.on(document, "mousemove", position);
|
||||
position(e);
|
||||
if (tt.style.opacity != null) tt.style.opacity = 1;
|
||||
return tt;
|
||||
}
|
||||
function rm(elt) {
|
||||
if (elt.parentNode) elt.parentNode.removeChild(elt);
|
||||
}
|
||||
function hideTooltip(tt) {
|
||||
if (!tt.parentNode) return;
|
||||
if (tt.style.opacity == null) rm(tt);
|
||||
tt.style.opacity = 0;
|
||||
setTimeout(function() { rm(tt); }, 600);
|
||||
}
|
||||
|
||||
function showTooltipFor(cm, e, content, node) {
|
||||
var tooltip = showTooltip(cm, e, content);
|
||||
function hide() {
|
||||
CodeMirror.off(node, "mouseout", hide);
|
||||
if (tooltip) { hideTooltip(tooltip); tooltip = null; }
|
||||
}
|
||||
var poll = setInterval(function() {
|
||||
if (tooltip) for (var n = node;; n = n.parentNode) {
|
||||
if (n && n.nodeType == 11) n = n.host;
|
||||
if (n == document.body) return;
|
||||
if (!n) { hide(); break; }
|
||||
}
|
||||
if (!tooltip) return clearInterval(poll);
|
||||
}, 400);
|
||||
CodeMirror.on(node, "mouseout", hide);
|
||||
}
|
||||
|
||||
function LintState(cm, conf, hasGutter) {
|
||||
this.marked = [];
|
||||
if (conf instanceof Function) conf = {getAnnotations: conf};
|
||||
if (!conf || conf === true) conf = {};
|
||||
this.options = {};
|
||||
this.linterOptions = conf.options || {};
|
||||
for (var prop in defaults) this.options[prop] = defaults[prop];
|
||||
for (var prop in conf) {
|
||||
if (defaults.hasOwnProperty(prop)) {
|
||||
if (conf[prop] != null) this.options[prop] = conf[prop];
|
||||
} else if (!conf.options) {
|
||||
this.linterOptions[prop] = conf[prop];
|
||||
}
|
||||
}
|
||||
this.timeout = null;
|
||||
this.hasGutter = hasGutter;
|
||||
this.onMouseOver = function(e) { onMouseOver(cm, e); };
|
||||
this.waitingFor = 0
|
||||
}
|
||||
|
||||
var defaults = {
|
||||
highlightLines: false,
|
||||
tooltips: true,
|
||||
delay: 500,
|
||||
lintOnChange: true,
|
||||
getAnnotations: null,
|
||||
async: false,
|
||||
selfContain: null,
|
||||
formatAnnotation: null,
|
||||
onUpdateLinting: null
|
||||
}
|
||||
|
||||
function clearMarks(cm) {
|
||||
var state = cm.state.lint;
|
||||
if (state.hasGutter) cm.clearGutter(GUTTER_ID);
|
||||
if (state.options.highlightLines) clearErrorLines(cm);
|
||||
for (var i = 0; i < state.marked.length; ++i)
|
||||
state.marked[i].clear();
|
||||
state.marked.length = 0;
|
||||
}
|
||||
|
||||
function clearErrorLines(cm) {
|
||||
cm.eachLine(function(line) {
|
||||
var has = line.wrapClass && /\bCodeMirror-lint-line-\w+\b/.exec(line.wrapClass);
|
||||
if (has) cm.removeLineClass(line, "wrap", has[0]);
|
||||
})
|
||||
}
|
||||
|
||||
function makeMarker(cm, labels, severity, multiple, tooltips) {
|
||||
var marker = document.createElement("div"), inner = marker;
|
||||
marker.className = "CodeMirror-lint-marker CodeMirror-lint-marker-" + severity;
|
||||
if (multiple) {
|
||||
inner = marker.appendChild(document.createElement("div"));
|
||||
inner.className = "CodeMirror-lint-marker CodeMirror-lint-marker-multiple";
|
||||
}
|
||||
|
||||
if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) {
|
||||
showTooltipFor(cm, e, labels, inner);
|
||||
});
|
||||
|
||||
return marker;
|
||||
}
|
||||
|
||||
function getMaxSeverity(a, b) {
|
||||
if (a == "error") return a;
|
||||
else return b;
|
||||
}
|
||||
|
||||
function groupByLine(annotations) {
|
||||
var lines = [];
|
||||
for (var i = 0; i < annotations.length; ++i) {
|
||||
var ann = annotations[i], line = ann.from.line;
|
||||
(lines[line] || (lines[line] = [])).push(ann);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
function annotationTooltip(ann) {
|
||||
var severity = ann.severity;
|
||||
if (!severity) severity = "error";
|
||||
var tip = document.createElement("div");
|
||||
tip.className = "CodeMirror-lint-message CodeMirror-lint-message-" + severity;
|
||||
if (typeof ann.messageHTML != 'undefined') {
|
||||
tip.innerHTML = ann.messageHTML;
|
||||
} else {
|
||||
tip.appendChild(document.createTextNode(ann.message));
|
||||
}
|
||||
return tip;
|
||||
}
|
||||
|
||||
function lintAsync(cm, getAnnotations) {
|
||||
var state = cm.state.lint
|
||||
var id = ++state.waitingFor
|
||||
function abort() {
|
||||
id = -1
|
||||
cm.off("change", abort)
|
||||
}
|
||||
cm.on("change", abort)
|
||||
getAnnotations(cm.getValue(), function(annotations, arg2) {
|
||||
cm.off("change", abort)
|
||||
if (state.waitingFor != id) return
|
||||
if (arg2 && annotations instanceof CodeMirror) annotations = arg2
|
||||
cm.operation(function() {updateLinting(cm, annotations)})
|
||||
}, state.linterOptions, cm);
|
||||
}
|
||||
|
||||
function startLinting(cm) {
|
||||
var state = cm.state.lint;
|
||||
if (!state) return;
|
||||
var options = state.options;
|
||||
/*
|
||||
* Passing rules in `options` property prevents JSHint (and other linters) from complaining
|
||||
* about unrecognized rules like `onUpdateLinting`, `delay`, `lintOnChange`, etc.
|
||||
*/
|
||||
var getAnnotations = options.getAnnotations || cm.getHelper(CodeMirror.Pos(0, 0), "lint");
|
||||
if (!getAnnotations) return;
|
||||
if (options.async || getAnnotations.async) {
|
||||
lintAsync(cm, getAnnotations)
|
||||
} else {
|
||||
var annotations = getAnnotations(cm.getValue(), state.linterOptions, cm);
|
||||
if (!annotations) return;
|
||||
if (annotations.then) annotations.then(function(issues) {
|
||||
cm.operation(function() {updateLinting(cm, issues)})
|
||||
});
|
||||
else cm.operation(function() {updateLinting(cm, annotations)})
|
||||
}
|
||||
}
|
||||
|
||||
function updateLinting(cm, annotationsNotSorted) {
|
||||
var state = cm.state.lint;
|
||||
if (!state) return;
|
||||
var options = state.options;
|
||||
clearMarks(cm);
|
||||
|
||||
var annotations = groupByLine(annotationsNotSorted);
|
||||
|
||||
for (var line = 0; line < annotations.length; ++line) {
|
||||
var anns = annotations[line];
|
||||
if (!anns) continue;
|
||||
|
||||
var maxSeverity = null;
|
||||
var tipLabel = state.hasGutter && document.createDocumentFragment();
|
||||
|
||||
for (var i = 0; i < anns.length; ++i) {
|
||||
var ann = anns[i];
|
||||
var severity = ann.severity;
|
||||
if (!severity) severity = "error";
|
||||
maxSeverity = getMaxSeverity(maxSeverity, severity);
|
||||
|
||||
if (options.formatAnnotation) ann = options.formatAnnotation(ann);
|
||||
if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann));
|
||||
|
||||
if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, {
|
||||
className: "CodeMirror-lint-mark CodeMirror-lint-mark-" + severity,
|
||||
__annotation: ann
|
||||
}));
|
||||
}
|
||||
if (state.hasGutter)
|
||||
cm.setGutterMarker(line, GUTTER_ID, makeMarker(cm, tipLabel, maxSeverity, anns.length > 1,
|
||||
options.tooltips));
|
||||
|
||||
if (options.highlightLines)
|
||||
cm.addLineClass(line, "wrap", LINT_LINE_ID + maxSeverity);
|
||||
}
|
||||
if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm);
|
||||
}
|
||||
|
||||
function onChange(cm) {
|
||||
var state = cm.state.lint;
|
||||
if (!state) return;
|
||||
clearTimeout(state.timeout);
|
||||
state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay);
|
||||
}
|
||||
|
||||
function popupTooltips(cm, annotations, e) {
|
||||
var target = e.target || e.srcElement;
|
||||
var tooltip = document.createDocumentFragment();
|
||||
for (var i = 0; i < annotations.length; i++) {
|
||||
var ann = annotations[i];
|
||||
tooltip.appendChild(annotationTooltip(ann));
|
||||
}
|
||||
showTooltipFor(cm, e, tooltip, target);
|
||||
}
|
||||
|
||||
function onMouseOver(cm, e) {
|
||||
var target = e.target || e.srcElement;
|
||||
if (!/\bCodeMirror-lint-mark-/.test(target.className)) return;
|
||||
var box = target.getBoundingClientRect(), x = (box.left + box.right) / 2, y = (box.top + box.bottom) / 2;
|
||||
var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, "client"));
|
||||
|
||||
var annotations = [];
|
||||
for (var i = 0; i < spans.length; ++i) {
|
||||
var ann = spans[i].__annotation;
|
||||
if (ann) annotations.push(ann);
|
||||
}
|
||||
if (annotations.length) popupTooltips(cm, annotations, e);
|
||||
}
|
||||
|
||||
CodeMirror.defineOption("lint", false, function(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init) {
|
||||
clearMarks(cm);
|
||||
if (cm.state.lint.options.lintOnChange !== false)
|
||||
cm.off("change", onChange);
|
||||
CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver);
|
||||
clearTimeout(cm.state.lint.timeout);
|
||||
delete cm.state.lint;
|
||||
}
|
||||
|
||||
if (val) {
|
||||
var gutters = cm.getOption("gutters"), hasLintGutter = false;
|
||||
for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true;
|
||||
var state = cm.state.lint = new LintState(cm, val, hasLintGutter);
|
||||
if (state.options.lintOnChange)
|
||||
cm.on("change", onChange);
|
||||
if (state.options.tooltips != false && state.options.tooltips != "gutter")
|
||||
CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver);
|
||||
|
||||
startLinting(cm);
|
||||
}
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("performLint", function() {
|
||||
startLinting(this);
|
||||
});
|
||||
});
|
||||
66
libraries/codemirror/addon/mode/loadmode.js
vendored
@@ -1,66 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"), "cjs");
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], function(CM) { mod(CM, "amd"); });
|
||||
else // Plain browser env
|
||||
mod(CodeMirror, "plain");
|
||||
})(function(CodeMirror, env) {
|
||||
if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js";
|
||||
|
||||
var loading = {};
|
||||
function splitCallback(cont, n) {
|
||||
var countDown = n;
|
||||
return function() { if (--countDown == 0) cont(); };
|
||||
}
|
||||
function ensureDeps(mode, cont, options) {
|
||||
var modeObj = CodeMirror.modes[mode], deps = modeObj && modeObj.dependencies;
|
||||
if (!deps) return cont();
|
||||
var missing = [];
|
||||
for (var i = 0; i < deps.length; ++i) {
|
||||
if (!CodeMirror.modes.hasOwnProperty(deps[i]))
|
||||
missing.push(deps[i]);
|
||||
}
|
||||
if (!missing.length) return cont();
|
||||
var split = splitCallback(cont, missing.length);
|
||||
for (var i = 0; i < missing.length; ++i)
|
||||
CodeMirror.requireMode(missing[i], split, options);
|
||||
}
|
||||
|
||||
CodeMirror.requireMode = function(mode, cont, options) {
|
||||
if (typeof mode != "string") mode = mode.name;
|
||||
if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont, options);
|
||||
if (loading.hasOwnProperty(mode)) return loading[mode].push(cont);
|
||||
|
||||
var file = options && options.path ? options.path(mode) : CodeMirror.modeURL.replace(/%N/g, mode);
|
||||
if (options && options.loadMode) {
|
||||
options.loadMode(file, function() { ensureDeps(mode, cont, options) })
|
||||
} else if (env == "plain") {
|
||||
var script = document.createElement("script");
|
||||
script.src = file;
|
||||
var others = document.getElementsByTagName("script")[0];
|
||||
var list = loading[mode] = [cont];
|
||||
CodeMirror.on(script, "load", function() {
|
||||
ensureDeps(mode, function() {
|
||||
for (var i = 0; i < list.length; ++i) list[i]();
|
||||
}, options);
|
||||
});
|
||||
others.parentNode.insertBefore(script, others);
|
||||
} else if (env == "cjs") {
|
||||
require(file);
|
||||
cont();
|
||||
} else if (env == "amd") {
|
||||
requirejs([file], cont);
|
||||
}
|
||||
};
|
||||
|
||||
CodeMirror.autoLoadMode = function(instance, mode, options) {
|
||||
if (!CodeMirror.modes.hasOwnProperty(mode))
|
||||
CodeMirror.requireMode(mode, function() {
|
||||
instance.setOption("mode", instance.getOption("mode"));
|
||||
}, options);
|
||||
};
|
||||
});
|
||||
136
libraries/codemirror/addon/mode/multiplex.js
vendored
@@ -1,136 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.multiplexingMode = function(outer /*, others */) {
|
||||
// Others should be {open, close, mode [, delimStyle] [, innerStyle] [, parseDelimiters]} objects
|
||||
var others = Array.prototype.slice.call(arguments, 1);
|
||||
|
||||
function indexOf(string, pattern, from, returnEnd) {
|
||||
if (typeof pattern == "string") {
|
||||
var found = string.indexOf(pattern, from);
|
||||
return returnEnd && found > -1 ? found + pattern.length : found;
|
||||
}
|
||||
var m = pattern.exec(from ? string.slice(from) : string);
|
||||
return m ? m.index + from + (returnEnd ? m[0].length : 0) : -1;
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function() {
|
||||
return {
|
||||
outer: CodeMirror.startState(outer),
|
||||
innerActive: null,
|
||||
inner: null,
|
||||
startingInner: false
|
||||
};
|
||||
},
|
||||
|
||||
copyState: function(state) {
|
||||
return {
|
||||
outer: CodeMirror.copyState(outer, state.outer),
|
||||
innerActive: state.innerActive,
|
||||
inner: state.innerActive && CodeMirror.copyState(state.innerActive.mode, state.inner),
|
||||
startingInner: state.startingInner
|
||||
};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (!state.innerActive) {
|
||||
var cutOff = Infinity, oldContent = stream.string;
|
||||
for (var i = 0; i < others.length; ++i) {
|
||||
var other = others[i];
|
||||
var found = indexOf(oldContent, other.open, stream.pos);
|
||||
if (found == stream.pos) {
|
||||
if (!other.parseDelimiters) stream.match(other.open);
|
||||
state.startingInner = !!other.parseDelimiters
|
||||
state.innerActive = other;
|
||||
|
||||
// Get the outer indent, making sure to handle CodeMirror.Pass
|
||||
var outerIndent = 0;
|
||||
if (outer.indent) {
|
||||
var possibleOuterIndent = outer.indent(state.outer, "", "");
|
||||
if (possibleOuterIndent !== CodeMirror.Pass) outerIndent = possibleOuterIndent;
|
||||
}
|
||||
|
||||
state.inner = CodeMirror.startState(other.mode, outerIndent);
|
||||
return other.delimStyle && (other.delimStyle + " " + other.delimStyle + "-open");
|
||||
} else if (found != -1 && found < cutOff) {
|
||||
cutOff = found;
|
||||
}
|
||||
}
|
||||
if (cutOff != Infinity) stream.string = oldContent.slice(0, cutOff);
|
||||
var outerToken = outer.token(stream, state.outer);
|
||||
if (cutOff != Infinity) stream.string = oldContent;
|
||||
return outerToken;
|
||||
} else {
|
||||
var curInner = state.innerActive, oldContent = stream.string;
|
||||
if (!curInner.close && stream.sol()) {
|
||||
state.innerActive = state.inner = null;
|
||||
return this.token(stream, state);
|
||||
}
|
||||
var found = curInner.close && !state.startingInner ?
|
||||
indexOf(oldContent, curInner.close, stream.pos, curInner.parseDelimiters) : -1;
|
||||
if (found == stream.pos && !curInner.parseDelimiters) {
|
||||
stream.match(curInner.close);
|
||||
state.innerActive = state.inner = null;
|
||||
return curInner.delimStyle && (curInner.delimStyle + " " + curInner.delimStyle + "-close");
|
||||
}
|
||||
if (found > -1) stream.string = oldContent.slice(0, found);
|
||||
var innerToken = curInner.mode.token(stream, state.inner);
|
||||
if (found > -1) stream.string = oldContent;
|
||||
else if (stream.pos > stream.start) state.startingInner = false
|
||||
|
||||
if (found == stream.pos && curInner.parseDelimiters)
|
||||
state.innerActive = state.inner = null;
|
||||
|
||||
if (curInner.innerStyle) {
|
||||
if (innerToken) innerToken = innerToken + " " + curInner.innerStyle;
|
||||
else innerToken = curInner.innerStyle;
|
||||
}
|
||||
|
||||
return innerToken;
|
||||
}
|
||||
},
|
||||
|
||||
indent: function(state, textAfter, line) {
|
||||
var mode = state.innerActive ? state.innerActive.mode : outer;
|
||||
if (!mode.indent) return CodeMirror.Pass;
|
||||
return mode.indent(state.innerActive ? state.inner : state.outer, textAfter, line);
|
||||
},
|
||||
|
||||
blankLine: function(state) {
|
||||
var mode = state.innerActive ? state.innerActive.mode : outer;
|
||||
if (mode.blankLine) {
|
||||
mode.blankLine(state.innerActive ? state.inner : state.outer);
|
||||
}
|
||||
if (!state.innerActive) {
|
||||
for (var i = 0; i < others.length; ++i) {
|
||||
var other = others[i];
|
||||
if (other.open === "\n") {
|
||||
state.innerActive = other;
|
||||
state.inner = CodeMirror.startState(other.mode, mode.indent ? mode.indent(state.outer, "", "") : 0);
|
||||
}
|
||||
}
|
||||
} else if (state.innerActive.close === "\n") {
|
||||
state.innerActive = state.inner = null;
|
||||
}
|
||||
},
|
||||
|
||||
electricChars: outer.electricChars,
|
||||
|
||||
innerMode: function(state) {
|
||||
return state.inner ? {state: state.inner, mode: state.innerActive.mode} : {state: state.outer, mode: outer};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
});
|
||||
90
libraries/codemirror/addon/mode/overlay.js
vendored
@@ -1,90 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
// Utility function that allows modes to be combined. The mode given
|
||||
// as the base argument takes care of most of the normal mode
|
||||
// functionality, but a second (typically simple) mode is used, which
|
||||
// can override the style of text. Both modes get to parse all of the
|
||||
// text, but when both assign a non-null style to a piece of code, the
|
||||
// overlay wins, unless the combine argument was true and not overridden,
|
||||
// or state.overlay.combineTokens was true, in which case the styles are
|
||||
// combined.
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.overlayMode = function(base, overlay, combine) {
|
||||
return {
|
||||
startState: function() {
|
||||
return {
|
||||
base: CodeMirror.startState(base),
|
||||
overlay: CodeMirror.startState(overlay),
|
||||
basePos: 0, baseCur: null,
|
||||
overlayPos: 0, overlayCur: null,
|
||||
streamSeen: null
|
||||
};
|
||||
},
|
||||
copyState: function(state) {
|
||||
return {
|
||||
base: CodeMirror.copyState(base, state.base),
|
||||
overlay: CodeMirror.copyState(overlay, state.overlay),
|
||||
basePos: state.basePos, baseCur: null,
|
||||
overlayPos: state.overlayPos, overlayCur: null
|
||||
};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (stream != state.streamSeen ||
|
||||
Math.min(state.basePos, state.overlayPos) < stream.start) {
|
||||
state.streamSeen = stream;
|
||||
state.basePos = state.overlayPos = stream.start;
|
||||
}
|
||||
|
||||
if (stream.start == state.basePos) {
|
||||
state.baseCur = base.token(stream, state.base);
|
||||
state.basePos = stream.pos;
|
||||
}
|
||||
if (stream.start == state.overlayPos) {
|
||||
stream.pos = stream.start;
|
||||
state.overlayCur = overlay.token(stream, state.overlay);
|
||||
state.overlayPos = stream.pos;
|
||||
}
|
||||
stream.pos = Math.min(state.basePos, state.overlayPos);
|
||||
|
||||
// state.overlay.combineTokens always takes precedence over combine,
|
||||
// unless set to null
|
||||
if (state.overlayCur == null) return state.baseCur;
|
||||
else if (state.baseCur != null &&
|
||||
state.overlay.combineTokens ||
|
||||
combine && state.overlay.combineTokens == null)
|
||||
return state.baseCur + " " + state.overlayCur;
|
||||
else return state.overlayCur;
|
||||
},
|
||||
|
||||
indent: base.indent && function(state, textAfter, line) {
|
||||
return base.indent(state.base, textAfter, line);
|
||||
},
|
||||
electricChars: base.electricChars,
|
||||
|
||||
innerMode: function(state) { return {state: state.base, mode: base}; },
|
||||
|
||||
blankLine: function(state) {
|
||||
var baseToken, overlayToken;
|
||||
if (base.blankLine) baseToken = base.blankLine(state.base);
|
||||
if (overlay.blankLine) overlayToken = overlay.blankLine(state.overlay);
|
||||
|
||||
return overlayToken == null ?
|
||||
baseToken :
|
||||
(combine && baseToken != null ? baseToken + " " + overlayToken : overlayToken);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
});
|
||||
216
libraries/codemirror/addon/mode/simple.js
vendored
@@ -1,216 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineSimpleMode = function(name, states) {
|
||||
CodeMirror.defineMode(name, function(config) {
|
||||
return CodeMirror.simpleMode(config, states);
|
||||
});
|
||||
};
|
||||
|
||||
CodeMirror.simpleMode = function(config, states) {
|
||||
ensureState(states, "start");
|
||||
var states_ = {}, meta = states.meta || {}, hasIndentation = false;
|
||||
for (var state in states) if (state != meta && states.hasOwnProperty(state)) {
|
||||
var list = states_[state] = [], orig = states[state];
|
||||
for (var i = 0; i < orig.length; i++) {
|
||||
var data = orig[i];
|
||||
list.push(new Rule(data, states));
|
||||
if (data.indent || data.dedent) hasIndentation = true;
|
||||
}
|
||||
}
|
||||
var mode = {
|
||||
startState: function() {
|
||||
return {state: "start", pending: null,
|
||||
local: null, localState: null,
|
||||
indent: hasIndentation ? [] : null};
|
||||
},
|
||||
copyState: function(state) {
|
||||
var s = {state: state.state, pending: state.pending,
|
||||
local: state.local, localState: null,
|
||||
indent: state.indent && state.indent.slice(0)};
|
||||
if (state.localState)
|
||||
s.localState = CodeMirror.copyState(state.local.mode, state.localState);
|
||||
if (state.stack)
|
||||
s.stack = state.stack.slice(0);
|
||||
for (var pers = state.persistentStates; pers; pers = pers.next)
|
||||
s.persistentStates = {mode: pers.mode,
|
||||
spec: pers.spec,
|
||||
state: pers.state == state.localState ? s.localState : CodeMirror.copyState(pers.mode, pers.state),
|
||||
next: s.persistentStates};
|
||||
return s;
|
||||
},
|
||||
token: tokenFunction(states_, config),
|
||||
innerMode: function(state) { return state.local && {mode: state.local.mode, state: state.localState}; },
|
||||
indent: indentFunction(states_, meta)
|
||||
};
|
||||
if (meta) for (var prop in meta) if (meta.hasOwnProperty(prop))
|
||||
mode[prop] = meta[prop];
|
||||
return mode;
|
||||
};
|
||||
|
||||
function ensureState(states, name) {
|
||||
if (!states.hasOwnProperty(name))
|
||||
throw new Error("Undefined state " + name + " in simple mode");
|
||||
}
|
||||
|
||||
function toRegex(val, caret) {
|
||||
if (!val) return /(?:)/;
|
||||
var flags = "";
|
||||
if (val instanceof RegExp) {
|
||||
if (val.ignoreCase) flags = "i";
|
||||
if (val.unicode) flags += "u"
|
||||
val = val.source;
|
||||
} else {
|
||||
val = String(val);
|
||||
}
|
||||
return new RegExp((caret === false ? "" : "^") + "(?:" + val + ")", flags);
|
||||
}
|
||||
|
||||
function asToken(val) {
|
||||
if (!val) return null;
|
||||
if (val.apply) return val
|
||||
if (typeof val == "string") return val.replace(/\./g, " ");
|
||||
var result = [];
|
||||
for (var i = 0; i < val.length; i++)
|
||||
result.push(val[i] && val[i].replace(/\./g, " "));
|
||||
return result;
|
||||
}
|
||||
|
||||
function Rule(data, states) {
|
||||
if (data.next || data.push) ensureState(states, data.next || data.push);
|
||||
this.regex = toRegex(data.regex);
|
||||
this.token = asToken(data.token);
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
function tokenFunction(states, config) {
|
||||
return function(stream, state) {
|
||||
if (state.pending) {
|
||||
var pend = state.pending.shift();
|
||||
if (state.pending.length == 0) state.pending = null;
|
||||
stream.pos += pend.text.length;
|
||||
return pend.token;
|
||||
}
|
||||
|
||||
if (state.local) {
|
||||
if (state.local.end && stream.match(state.local.end)) {
|
||||
var tok = state.local.endToken || null;
|
||||
state.local = state.localState = null;
|
||||
return tok;
|
||||
} else {
|
||||
var tok = state.local.mode.token(stream, state.localState), m;
|
||||
if (state.local.endScan && (m = state.local.endScan.exec(stream.current())))
|
||||
stream.pos = stream.start + m.index;
|
||||
return tok;
|
||||
}
|
||||
}
|
||||
|
||||
var curState = states[state.state];
|
||||
for (var i = 0; i < curState.length; i++) {
|
||||
var rule = curState[i];
|
||||
var matches = (!rule.data.sol || stream.sol()) && stream.match(rule.regex);
|
||||
if (matches) {
|
||||
if (rule.data.next) {
|
||||
state.state = rule.data.next;
|
||||
} else if (rule.data.push) {
|
||||
(state.stack || (state.stack = [])).push(state.state);
|
||||
state.state = rule.data.push;
|
||||
} else if (rule.data.pop && state.stack && state.stack.length) {
|
||||
state.state = state.stack.pop();
|
||||
}
|
||||
|
||||
if (rule.data.mode)
|
||||
enterLocalMode(config, state, rule.data.mode, rule.token);
|
||||
if (rule.data.indent)
|
||||
state.indent.push(stream.indentation() + config.indentUnit);
|
||||
if (rule.data.dedent)
|
||||
state.indent.pop();
|
||||
var token = rule.token
|
||||
if (token && token.apply) token = token(matches)
|
||||
if (matches.length > 2 && rule.token && typeof rule.token != "string") {
|
||||
for (var j = 2; j < matches.length; j++)
|
||||
if (matches[j])
|
||||
(state.pending || (state.pending = [])).push({text: matches[j], token: rule.token[j - 1]});
|
||||
stream.backUp(matches[0].length - (matches[1] ? matches[1].length : 0));
|
||||
return token[0];
|
||||
} else if (token && token.join) {
|
||||
return token[0];
|
||||
} else {
|
||||
return token;
|
||||
}
|
||||
}
|
||||
}
|
||||
stream.next();
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
function cmp(a, b) {
|
||||
if (a === b) return true;
|
||||
if (!a || typeof a != "object" || !b || typeof b != "object") return false;
|
||||
var props = 0;
|
||||
for (var prop in a) if (a.hasOwnProperty(prop)) {
|
||||
if (!b.hasOwnProperty(prop) || !cmp(a[prop], b[prop])) return false;
|
||||
props++;
|
||||
}
|
||||
for (var prop in b) if (b.hasOwnProperty(prop)) props--;
|
||||
return props == 0;
|
||||
}
|
||||
|
||||
function enterLocalMode(config, state, spec, token) {
|
||||
var pers;
|
||||
if (spec.persistent) for (var p = state.persistentStates; p && !pers; p = p.next)
|
||||
if (spec.spec ? cmp(spec.spec, p.spec) : spec.mode == p.mode) pers = p;
|
||||
var mode = pers ? pers.mode : spec.mode || CodeMirror.getMode(config, spec.spec);
|
||||
var lState = pers ? pers.state : CodeMirror.startState(mode);
|
||||
if (spec.persistent && !pers)
|
||||
state.persistentStates = {mode: mode, spec: spec.spec, state: lState, next: state.persistentStates};
|
||||
|
||||
state.localState = lState;
|
||||
state.local = {mode: mode,
|
||||
end: spec.end && toRegex(spec.end),
|
||||
endScan: spec.end && spec.forceEnd !== false && toRegex(spec.end, false),
|
||||
endToken: token && token.join ? token[token.length - 1] : token};
|
||||
}
|
||||
|
||||
function indexOf(val, arr) {
|
||||
for (var i = 0; i < arr.length; i++) if (arr[i] === val) return true;
|
||||
}
|
||||
|
||||
function indentFunction(states, meta) {
|
||||
return function(state, textAfter, line) {
|
||||
if (state.local && state.local.mode.indent)
|
||||
return state.local.mode.indent(state.localState, textAfter, line);
|
||||
if (state.indent == null || state.local || meta.dontIndentStates && indexOf(state.state, meta.dontIndentStates) > -1)
|
||||
return CodeMirror.Pass;
|
||||
|
||||
var pos = state.indent.length - 1, rules = states[state.state];
|
||||
scan: for (;;) {
|
||||
for (var i = 0; i < rules.length; i++) {
|
||||
var rule = rules[i];
|
||||
if (rule.data.dedent && rule.data.dedentIfLineStart !== false) {
|
||||
var m = rule.regex.exec(textAfter);
|
||||
if (m && m[0]) {
|
||||
pos--;
|
||||
if (rule.next || rule.push) rules = states[rule.next || rule.push];
|
||||
textAfter = textAfter.slice(m[0].length);
|
||||
continue scan;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return pos < 0 ? 0 : state.indent[pos];
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -1,167 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
// Highlighting text that matches the selection
|
||||
//
|
||||
// Defines an option highlightSelectionMatches, which, when enabled,
|
||||
// will style strings that match the selection throughout the
|
||||
// document.
|
||||
//
|
||||
// The option can be set to true to simply enable it, or to a
|
||||
// {minChars, style, wordsOnly, showToken, delay} object to explicitly
|
||||
// configure it. minChars is the minimum amount of characters that should be
|
||||
// selected for the behavior to occur, and style is the token style to
|
||||
// apply to the matches. This will be prefixed by "cm-" to create an
|
||||
// actual CSS class name. If wordsOnly is enabled, the matches will be
|
||||
// highlighted only if the selected text is a word. showToken, when enabled,
|
||||
// will cause the current token to be highlighted when nothing is selected.
|
||||
// delay is used to specify how much time to wait, in milliseconds, before
|
||||
// highlighting the matches. If annotateScrollbar is enabled, the occurrences
|
||||
// will be highlighted on the scrollbar via the matchesonscrollbar addon.
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"), require("./matchesonscrollbar"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "./matchesonscrollbar"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var defaults = {
|
||||
style: "matchhighlight",
|
||||
minChars: 2,
|
||||
delay: 100,
|
||||
wordsOnly: false,
|
||||
annotateScrollbar: false,
|
||||
showToken: false,
|
||||
trim: true
|
||||
}
|
||||
|
||||
function State(options) {
|
||||
this.options = {}
|
||||
for (var name in defaults)
|
||||
this.options[name] = (options && options.hasOwnProperty(name) ? options : defaults)[name]
|
||||
this.overlay = this.timeout = null;
|
||||
this.matchesonscroll = null;
|
||||
this.active = false;
|
||||
}
|
||||
|
||||
CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init) {
|
||||
removeOverlay(cm);
|
||||
clearTimeout(cm.state.matchHighlighter.timeout);
|
||||
cm.state.matchHighlighter = null;
|
||||
cm.off("cursorActivity", cursorActivity);
|
||||
cm.off("focus", onFocus)
|
||||
}
|
||||
if (val) {
|
||||
var state = cm.state.matchHighlighter = new State(val);
|
||||
if (cm.hasFocus()) {
|
||||
state.active = true
|
||||
highlightMatches(cm)
|
||||
} else {
|
||||
cm.on("focus", onFocus)
|
||||
}
|
||||
cm.on("cursorActivity", cursorActivity);
|
||||
}
|
||||
});
|
||||
|
||||
function cursorActivity(cm) {
|
||||
var state = cm.state.matchHighlighter;
|
||||
if (state.active || cm.hasFocus()) scheduleHighlight(cm, state)
|
||||
}
|
||||
|
||||
function onFocus(cm) {
|
||||
var state = cm.state.matchHighlighter
|
||||
if (!state.active) {
|
||||
state.active = true
|
||||
scheduleHighlight(cm, state)
|
||||
}
|
||||
}
|
||||
|
||||
function scheduleHighlight(cm, state) {
|
||||
clearTimeout(state.timeout);
|
||||
state.timeout = setTimeout(function() {highlightMatches(cm);}, state.options.delay);
|
||||
}
|
||||
|
||||
function addOverlay(cm, query, hasBoundary, style) {
|
||||
var state = cm.state.matchHighlighter;
|
||||
cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style));
|
||||
if (state.options.annotateScrollbar && cm.showMatchesOnScrollbar) {
|
||||
var searchFor = hasBoundary ? new RegExp((/\w/.test(query.charAt(0)) ? "\\b" : "") +
|
||||
query.replace(/[\\\[.+*?(){|^$]/g, "\\$&") +
|
||||
(/\w/.test(query.charAt(query.length - 1)) ? "\\b" : "")) : query;
|
||||
state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, false,
|
||||
{className: "CodeMirror-selection-highlight-scrollbar"});
|
||||
}
|
||||
}
|
||||
|
||||
function removeOverlay(cm) {
|
||||
var state = cm.state.matchHighlighter;
|
||||
if (state.overlay) {
|
||||
cm.removeOverlay(state.overlay);
|
||||
state.overlay = null;
|
||||
if (state.matchesonscroll) {
|
||||
state.matchesonscroll.clear();
|
||||
state.matchesonscroll = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function highlightMatches(cm) {
|
||||
cm.operation(function() {
|
||||
var state = cm.state.matchHighlighter;
|
||||
removeOverlay(cm);
|
||||
if (!cm.somethingSelected() && state.options.showToken) {
|
||||
var re = state.options.showToken === true ? /[\w$]/ : state.options.showToken;
|
||||
var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start;
|
||||
while (start && re.test(line.charAt(start - 1))) --start;
|
||||
while (end < line.length && re.test(line.charAt(end))) ++end;
|
||||
if (start < end)
|
||||
addOverlay(cm, line.slice(start, end), re, state.options.style);
|
||||
return;
|
||||
}
|
||||
var from = cm.getCursor("from"), to = cm.getCursor("to");
|
||||
if (from.line != to.line) return;
|
||||
if (state.options.wordsOnly && !isWord(cm, from, to)) return;
|
||||
var selection = cm.getRange(from, to)
|
||||
if (state.options.trim) selection = selection.replace(/^\s+|\s+$/g, "")
|
||||
if (selection.length >= state.options.minChars)
|
||||
addOverlay(cm, selection, false, state.options.style);
|
||||
});
|
||||
}
|
||||
|
||||
function isWord(cm, from, to) {
|
||||
var str = cm.getRange(from, to);
|
||||
if (str.match(/^\w+$/) !== null) {
|
||||
if (from.ch > 0) {
|
||||
var pos = {line: from.line, ch: from.ch - 1};
|
||||
var chr = cm.getRange(pos, from);
|
||||
if (chr.match(/\W/) === null) return false;
|
||||
}
|
||||
if (to.ch < cm.getLine(from.line).length) {
|
||||
var pos = {line: to.line, ch: to.ch + 1};
|
||||
var chr = cm.getRange(to, pos);
|
||||
if (chr.match(/\W/) === null) return false;
|
||||
}
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
function boundariesAround(stream, re) {
|
||||
return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) &&
|
||||
(stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos)));
|
||||
}
|
||||
|
||||
function makeOverlay(query, hasBoundary, style) {
|
||||
return {token: function(stream) {
|
||||
if (stream.match(query) &&
|
||||
(!hasBoundary || boundariesAround(stream, hasBoundary)))
|
||||
return style;
|
||||
stream.next();
|
||||
stream.skipTo(query.charAt(0)) || stream.skipToEnd();
|
||||
}};
|
||||
}
|
||||
});
|
||||
@@ -1,344 +0,0 @@
|
||||
/* BASICS */
|
||||
|
||||
.CodeMirror {
|
||||
/* Set height, width, borders, and global font properties here */
|
||||
font-family: monospace;
|
||||
height: 300px;
|
||||
color: black;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
/* PADDING */
|
||||
|
||||
.CodeMirror-lines {
|
||||
padding: 4px 0; /* Vertical padding around content */
|
||||
}
|
||||
.CodeMirror pre.CodeMirror-line,
|
||||
.CodeMirror pre.CodeMirror-line-like {
|
||||
padding: 0 4px; /* Horizontal padding of content */
|
||||
}
|
||||
|
||||
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
|
||||
background-color: white; /* The little square between H and V scrollbars */
|
||||
}
|
||||
|
||||
/* GUTTER */
|
||||
|
||||
.CodeMirror-gutters {
|
||||
border-right: 1px solid #ddd;
|
||||
background-color: #f7f7f7;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.CodeMirror-linenumbers {}
|
||||
.CodeMirror-linenumber {
|
||||
padding: 0 3px 0 5px;
|
||||
min-width: 20px;
|
||||
text-align: right;
|
||||
color: #999;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.CodeMirror-guttermarker { color: black; }
|
||||
.CodeMirror-guttermarker-subtle { color: #999; }
|
||||
|
||||
/* CURSOR */
|
||||
|
||||
.CodeMirror-cursor {
|
||||
border-left: 1px solid black;
|
||||
border-right: none;
|
||||
width: 0;
|
||||
}
|
||||
/* Shown when moving in bi-directional text */
|
||||
.CodeMirror div.CodeMirror-secondarycursor {
|
||||
border-left: 1px solid silver;
|
||||
}
|
||||
.cm-fat-cursor .CodeMirror-cursor {
|
||||
width: auto;
|
||||
border: 0 !important;
|
||||
background: #7e7;
|
||||
}
|
||||
.cm-fat-cursor div.CodeMirror-cursors {
|
||||
z-index: 1;
|
||||
}
|
||||
.cm-fat-cursor .CodeMirror-line::selection,
|
||||
.cm-fat-cursor .CodeMirror-line > span::selection,
|
||||
.cm-fat-cursor .CodeMirror-line > span > span::selection { background: transparent; }
|
||||
.cm-fat-cursor .CodeMirror-line::-moz-selection,
|
||||
.cm-fat-cursor .CodeMirror-line > span::-moz-selection,
|
||||
.cm-fat-cursor .CodeMirror-line > span > span::-moz-selection { background: transparent; }
|
||||
.cm-fat-cursor { caret-color: transparent; }
|
||||
@-moz-keyframes blink {
|
||||
0% {}
|
||||
50% { background-color: transparent; }
|
||||
100% {}
|
||||
}
|
||||
@-webkit-keyframes blink {
|
||||
0% {}
|
||||
50% { background-color: transparent; }
|
||||
100% {}
|
||||
}
|
||||
@keyframes blink {
|
||||
0% {}
|
||||
50% { background-color: transparent; }
|
||||
100% {}
|
||||
}
|
||||
|
||||
/* Can style cursor different in overwrite (non-insert) mode */
|
||||
.CodeMirror-overwrite .CodeMirror-cursor {}
|
||||
|
||||
.cm-tab { display: inline-block; text-decoration: inherit; }
|
||||
|
||||
.CodeMirror-rulers {
|
||||
position: absolute;
|
||||
left: 0; right: 0; top: -50px; bottom: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.CodeMirror-ruler {
|
||||
border-left: 1px solid #ccc;
|
||||
top: 0; bottom: 0;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* DEFAULT THEME */
|
||||
|
||||
.cm-s-default .cm-header {color: blue;}
|
||||
.cm-s-default .cm-quote {color: #090;}
|
||||
.cm-negative {color: #d44;}
|
||||
.cm-positive {color: #292;}
|
||||
.cm-header, .cm-strong {font-weight: bold;}
|
||||
.cm-em {font-style: italic;}
|
||||
.cm-link {text-decoration: underline;}
|
||||
.cm-strikethrough {text-decoration: line-through;}
|
||||
|
||||
.cm-s-default .cm-keyword {color: #708;}
|
||||
.cm-s-default .cm-atom {color: #219;}
|
||||
.cm-s-default .cm-number {color: #164;}
|
||||
.cm-s-default .cm-def {color: #00f;}
|
||||
.cm-s-default .cm-variable,
|
||||
.cm-s-default .cm-punctuation,
|
||||
.cm-s-default .cm-property,
|
||||
.cm-s-default .cm-operator {}
|
||||
.cm-s-default .cm-variable-2 {color: #05a;}
|
||||
.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
|
||||
.cm-s-default .cm-comment {color: #a50;}
|
||||
.cm-s-default .cm-string {color: #a11;}
|
||||
.cm-s-default .cm-string-2 {color: #f50;}
|
||||
.cm-s-default .cm-meta {color: #555;}
|
||||
.cm-s-default .cm-qualifier {color: #555;}
|
||||
.cm-s-default .cm-builtin {color: #30a;}
|
||||
.cm-s-default .cm-bracket {color: #997;}
|
||||
.cm-s-default .cm-tag {color: #170;}
|
||||
.cm-s-default .cm-attribute {color: #00c;}
|
||||
.cm-s-default .cm-hr {color: #999;}
|
||||
.cm-s-default .cm-link {color: #00c;}
|
||||
|
||||
.cm-s-default .cm-error {color: #f00;}
|
||||
.cm-invalidchar {color: #f00;}
|
||||
|
||||
.CodeMirror-composing { border-bottom: 2px solid; }
|
||||
|
||||
/* Default styles for common addons */
|
||||
|
||||
div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
|
||||
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
|
||||
.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
|
||||
.CodeMirror-activeline-background {background: #e8f2ff;}
|
||||
|
||||
/* STOP */
|
||||
|
||||
/* The rest of this file contains styles related to the mechanics of
|
||||
the editor. You probably shouldn't touch them. */
|
||||
|
||||
.CodeMirror {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.CodeMirror-scroll {
|
||||
overflow: scroll !important; /* Things will break if this is overridden */
|
||||
/* 50px is the magic margin used to hide the element's real scrollbars */
|
||||
/* See overflow: hidden in .CodeMirror */
|
||||
margin-bottom: -50px; margin-right: -50px;
|
||||
padding-bottom: 50px;
|
||||
height: 100%;
|
||||
outline: none; /* Prevent dragging from highlighting the element */
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
}
|
||||
.CodeMirror-sizer {
|
||||
position: relative;
|
||||
border-right: 50px solid transparent;
|
||||
}
|
||||
|
||||
/* The fake, visible scrollbars. Used to force redraw during scrolling
|
||||
before actual scrolling happens, thus preventing shaking and
|
||||
flickering artifacts. */
|
||||
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
|
||||
position: absolute;
|
||||
z-index: 6;
|
||||
display: none;
|
||||
outline: none;
|
||||
}
|
||||
.CodeMirror-vscrollbar {
|
||||
right: 0; top: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.CodeMirror-hscrollbar {
|
||||
bottom: 0; left: 0;
|
||||
overflow-y: hidden;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
.CodeMirror-scrollbar-filler {
|
||||
right: 0; bottom: 0;
|
||||
}
|
||||
.CodeMirror-gutter-filler {
|
||||
left: 0; bottom: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-gutters {
|
||||
position: absolute; left: 0; top: 0;
|
||||
min-height: 100%;
|
||||
z-index: 3;
|
||||
}
|
||||
.CodeMirror-gutter {
|
||||
white-space: normal;
|
||||
height: 100%;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-bottom: -50px;
|
||||
}
|
||||
.CodeMirror-gutter-wrapper {
|
||||
position: absolute;
|
||||
z-index: 4;
|
||||
background: none !important;
|
||||
border: none !important;
|
||||
}
|
||||
.CodeMirror-gutter-background {
|
||||
position: absolute;
|
||||
top: 0; bottom: 0;
|
||||
z-index: 4;
|
||||
}
|
||||
.CodeMirror-gutter-elt {
|
||||
position: absolute;
|
||||
cursor: default;
|
||||
z-index: 4;
|
||||
}
|
||||
.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
|
||||
.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
|
||||
|
||||
.CodeMirror-lines {
|
||||
cursor: text;
|
||||
min-height: 1px; /* prevents collapsing before first draw */
|
||||
}
|
||||
.CodeMirror pre.CodeMirror-line,
|
||||
.CodeMirror pre.CodeMirror-line-like {
|
||||
/* Reset some styles that the rest of the page might have set */
|
||||
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
|
||||
border-width: 0;
|
||||
background: transparent;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
margin: 0;
|
||||
white-space: pre;
|
||||
word-wrap: normal;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-webkit-font-variant-ligatures: contextual;
|
||||
font-variant-ligatures: contextual;
|
||||
}
|
||||
.CodeMirror-wrap pre.CodeMirror-line,
|
||||
.CodeMirror-wrap pre.CodeMirror-line-like {
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
.CodeMirror-linebackground {
|
||||
position: absolute;
|
||||
left: 0; right: 0; top: 0; bottom: 0;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-linewidget {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
padding: 0.1px; /* Force widget margins to stay inside of the container */
|
||||
}
|
||||
|
||||
.CodeMirror-widget {}
|
||||
|
||||
.CodeMirror-rtl pre { direction: rtl; }
|
||||
|
||||
.CodeMirror-code {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Force content-box sizing for the elements where we expect it */
|
||||
.CodeMirror-scroll,
|
||||
.CodeMirror-sizer,
|
||||
.CodeMirror-gutter,
|
||||
.CodeMirror-gutters,
|
||||
.CodeMirror-linenumber {
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.CodeMirror-measure {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.CodeMirror-cursor {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
}
|
||||
.CodeMirror-measure pre { position: static; }
|
||||
|
||||
div.CodeMirror-cursors {
|
||||
visibility: hidden;
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
}
|
||||
div.CodeMirror-dragcursors {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.CodeMirror-focused div.CodeMirror-cursors {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.CodeMirror-selected { background: #d9d9d9; }
|
||||
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
|
||||
.CodeMirror-crosshair { cursor: crosshair; }
|
||||
.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
|
||||
.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
|
||||
|
||||
.cm-searching {
|
||||
background-color: #ffa;
|
||||
background-color: rgba(255, 255, 0, .4);
|
||||
}
|
||||
|
||||
/* Used to force a border model for a node */
|
||||
.cm-force-border { padding-right: .1px; }
|
||||
|
||||
@media print {
|
||||
/* Hide the cursor when printing */
|
||||
.CodeMirror div.CodeMirror-cursors {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
/* See issue #2901 */
|
||||
.cm-tab-wrap-hack:after { content: ''; }
|
||||
|
||||
/* Help users use markselection to safely style text background */
|
||||
span.CodeMirror-selectedtext { background: none; }
|
||||
5978
libraries/codemirror/keymap/vim.js
vendored
174
libraries/codemirror/mode/apl/apl.js
vendored
@@ -1,174 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineMode("apl", function() {
|
||||
var builtInOps = {
|
||||
".": "innerProduct",
|
||||
"\\": "scan",
|
||||
"/": "reduce",
|
||||
"⌿": "reduce1Axis",
|
||||
"⍀": "scan1Axis",
|
||||
"¨": "each",
|
||||
"⍣": "power"
|
||||
};
|
||||
var builtInFuncs = {
|
||||
"+": ["conjugate", "add"],
|
||||
"−": ["negate", "subtract"],
|
||||
"×": ["signOf", "multiply"],
|
||||
"÷": ["reciprocal", "divide"],
|
||||
"⌈": ["ceiling", "greaterOf"],
|
||||
"⌊": ["floor", "lesserOf"],
|
||||
"∣": ["absolute", "residue"],
|
||||
"⍳": ["indexGenerate", "indexOf"],
|
||||
"?": ["roll", "deal"],
|
||||
"⋆": ["exponentiate", "toThePowerOf"],
|
||||
"⍟": ["naturalLog", "logToTheBase"],
|
||||
"○": ["piTimes", "circularFuncs"],
|
||||
"!": ["factorial", "binomial"],
|
||||
"⌹": ["matrixInverse", "matrixDivide"],
|
||||
"<": [null, "lessThan"],
|
||||
"≤": [null, "lessThanOrEqual"],
|
||||
"=": [null, "equals"],
|
||||
">": [null, "greaterThan"],
|
||||
"≥": [null, "greaterThanOrEqual"],
|
||||
"≠": [null, "notEqual"],
|
||||
"≡": ["depth", "match"],
|
||||
"≢": [null, "notMatch"],
|
||||
"∈": ["enlist", "membership"],
|
||||
"⍷": [null, "find"],
|
||||
"∪": ["unique", "union"],
|
||||
"∩": [null, "intersection"],
|
||||
"∼": ["not", "without"],
|
||||
"∨": [null, "or"],
|
||||
"∧": [null, "and"],
|
||||
"⍱": [null, "nor"],
|
||||
"⍲": [null, "nand"],
|
||||
"⍴": ["shapeOf", "reshape"],
|
||||
",": ["ravel", "catenate"],
|
||||
"⍪": [null, "firstAxisCatenate"],
|
||||
"⌽": ["reverse", "rotate"],
|
||||
"⊖": ["axis1Reverse", "axis1Rotate"],
|
||||
"⍉": ["transpose", null],
|
||||
"↑": ["first", "take"],
|
||||
"↓": [null, "drop"],
|
||||
"⊂": ["enclose", "partitionWithAxis"],
|
||||
"⊃": ["diclose", "pick"],
|
||||
"⌷": [null, "index"],
|
||||
"⍋": ["gradeUp", null],
|
||||
"⍒": ["gradeDown", null],
|
||||
"⊤": ["encode", null],
|
||||
"⊥": ["decode", null],
|
||||
"⍕": ["format", "formatByExample"],
|
||||
"⍎": ["execute", null],
|
||||
"⊣": ["stop", "left"],
|
||||
"⊢": ["pass", "right"]
|
||||
};
|
||||
|
||||
var isOperator = /[\.\/⌿⍀¨⍣]/;
|
||||
var isNiladic = /⍬/;
|
||||
var isFunction = /[\+−×÷⌈⌊∣⍳\?⋆⍟○!⌹<≤=>≥≠≡≢∈⍷∪∩∼∨∧⍱⍲⍴,⍪⌽⊖⍉↑↓⊂⊃⌷⍋⍒⊤⊥⍕⍎⊣⊢]/;
|
||||
var isArrow = /←/;
|
||||
var isComment = /[⍝#].*$/;
|
||||
|
||||
var stringEater = function(type) {
|
||||
var prev;
|
||||
prev = false;
|
||||
return function(c) {
|
||||
prev = c;
|
||||
if (c === type) {
|
||||
return prev === "\\";
|
||||
}
|
||||
return true;
|
||||
};
|
||||
};
|
||||
return {
|
||||
startState: function() {
|
||||
return {
|
||||
prev: false,
|
||||
func: false,
|
||||
op: false,
|
||||
string: false,
|
||||
escape: false
|
||||
};
|
||||
},
|
||||
token: function(stream, state) {
|
||||
var ch, funcName;
|
||||
if (stream.eatSpace()) {
|
||||
return null;
|
||||
}
|
||||
ch = stream.next();
|
||||
if (ch === '"' || ch === "'") {
|
||||
stream.eatWhile(stringEater(ch));
|
||||
stream.next();
|
||||
state.prev = true;
|
||||
return "string";
|
||||
}
|
||||
if (/[\[{\(]/.test(ch)) {
|
||||
state.prev = false;
|
||||
return null;
|
||||
}
|
||||
if (/[\]}\)]/.test(ch)) {
|
||||
state.prev = true;
|
||||
return null;
|
||||
}
|
||||
if (isNiladic.test(ch)) {
|
||||
state.prev = false;
|
||||
return "niladic";
|
||||
}
|
||||
if (/[¯\d]/.test(ch)) {
|
||||
if (state.func) {
|
||||
state.func = false;
|
||||
state.prev = false;
|
||||
} else {
|
||||
state.prev = true;
|
||||
}
|
||||
stream.eatWhile(/[\w\.]/);
|
||||
return "number";
|
||||
}
|
||||
if (isOperator.test(ch)) {
|
||||
return "operator apl-" + builtInOps[ch];
|
||||
}
|
||||
if (isArrow.test(ch)) {
|
||||
return "apl-arrow";
|
||||
}
|
||||
if (isFunction.test(ch)) {
|
||||
funcName = "apl-";
|
||||
if (builtInFuncs[ch] != null) {
|
||||
if (state.prev) {
|
||||
funcName += builtInFuncs[ch][1];
|
||||
} else {
|
||||
funcName += builtInFuncs[ch][0];
|
||||
}
|
||||
}
|
||||
state.func = true;
|
||||
state.prev = false;
|
||||
return "function " + funcName;
|
||||
}
|
||||
if (isComment.test(ch)) {
|
||||
stream.skipToEnd();
|
||||
return "comment";
|
||||
}
|
||||
if (ch === "∘" && stream.peek() === ".") {
|
||||
stream.next();
|
||||
return "function jot-dot";
|
||||
}
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
state.prev = true;
|
||||
return "keyword";
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/apl", "apl");
|
||||
|
||||
});
|
||||
@@ -1,74 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
function errorIfNotEmpty(stream) {
|
||||
var nonWS = stream.match(/^\s*\S/);
|
||||
stream.skipToEnd();
|
||||
return nonWS ? "error" : null;
|
||||
}
|
||||
|
||||
CodeMirror.defineMode("asciiarmor", function() {
|
||||
return {
|
||||
token: function(stream, state) {
|
||||
var m;
|
||||
if (state.state == "top") {
|
||||
if (stream.sol() && (m = stream.match(/^-----BEGIN (.*)?-----\s*$/))) {
|
||||
state.state = "headers";
|
||||
state.type = m[1];
|
||||
return "tag";
|
||||
}
|
||||
return errorIfNotEmpty(stream);
|
||||
} else if (state.state == "headers") {
|
||||
if (stream.sol() && stream.match(/^\w+:/)) {
|
||||
state.state = "header";
|
||||
return "atom";
|
||||
} else {
|
||||
var result = errorIfNotEmpty(stream);
|
||||
if (result) state.state = "body";
|
||||
return result;
|
||||
}
|
||||
} else if (state.state == "header") {
|
||||
stream.skipToEnd();
|
||||
state.state = "headers";
|
||||
return "string";
|
||||
} else if (state.state == "body") {
|
||||
if (stream.sol() && (m = stream.match(/^-----END (.*)?-----\s*$/))) {
|
||||
if (m[1] != state.type) return "error";
|
||||
state.state = "end";
|
||||
return "tag";
|
||||
} else {
|
||||
if (stream.eatWhile(/[A-Za-z0-9+\/=]/)) {
|
||||
return null;
|
||||
} else {
|
||||
stream.next();
|
||||
return "error";
|
||||
}
|
||||
}
|
||||
} else if (state.state == "end") {
|
||||
return errorIfNotEmpty(stream);
|
||||
}
|
||||
},
|
||||
blankLine: function(state) {
|
||||
if (state.state == "headers") state.state = "body";
|
||||
},
|
||||
startState: function() {
|
||||
return {state: "top", type: null};
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("application/pgp", "asciiarmor");
|
||||
CodeMirror.defineMIME("application/pgp-encrypted", "asciiarmor");
|
||||
CodeMirror.defineMIME("application/pgp-keys", "asciiarmor");
|
||||
CodeMirror.defineMIME("application/pgp-signature", "asciiarmor");
|
||||
});
|
||||
204
libraries/codemirror/mode/asn.1/asn.1.js
vendored
@@ -1,204 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineMode("asn.1", function(config, parserConfig) {
|
||||
var indentUnit = config.indentUnit,
|
||||
keywords = parserConfig.keywords || {},
|
||||
cmipVerbs = parserConfig.cmipVerbs || {},
|
||||
compareTypes = parserConfig.compareTypes || {},
|
||||
status = parserConfig.status || {},
|
||||
tags = parserConfig.tags || {},
|
||||
storage = parserConfig.storage || {},
|
||||
modifier = parserConfig.modifier || {},
|
||||
accessTypes = parserConfig.accessTypes|| {},
|
||||
multiLineStrings = parserConfig.multiLineStrings,
|
||||
indentStatements = parserConfig.indentStatements !== false;
|
||||
var isOperatorChar = /[\|\^]/;
|
||||
var curPunc;
|
||||
|
||||
function tokenBase(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (ch == '"' || ch == "'") {
|
||||
state.tokenize = tokenString(ch);
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
if (/[\[\]\(\){}:=,;]/.test(ch)) {
|
||||
curPunc = ch;
|
||||
return "punctuation";
|
||||
}
|
||||
if (ch == "-"){
|
||||
if (stream.eat("-")) {
|
||||
stream.skipToEnd();
|
||||
return "comment";
|
||||
}
|
||||
}
|
||||
if (/\d/.test(ch)) {
|
||||
stream.eatWhile(/[\w\.]/);
|
||||
return "number";
|
||||
}
|
||||
if (isOperatorChar.test(ch)) {
|
||||
stream.eatWhile(isOperatorChar);
|
||||
return "operator";
|
||||
}
|
||||
|
||||
stream.eatWhile(/[\w\-]/);
|
||||
var cur = stream.current();
|
||||
if (keywords.propertyIsEnumerable(cur)) return "keyword";
|
||||
if (cmipVerbs.propertyIsEnumerable(cur)) return "variable cmipVerbs";
|
||||
if (compareTypes.propertyIsEnumerable(cur)) return "atom compareTypes";
|
||||
if (status.propertyIsEnumerable(cur)) return "comment status";
|
||||
if (tags.propertyIsEnumerable(cur)) return "variable-3 tags";
|
||||
if (storage.propertyIsEnumerable(cur)) return "builtin storage";
|
||||
if (modifier.propertyIsEnumerable(cur)) return "string-2 modifier";
|
||||
if (accessTypes.propertyIsEnumerable(cur)) return "atom accessTypes";
|
||||
|
||||
return "variable";
|
||||
}
|
||||
|
||||
function tokenString(quote) {
|
||||
return function(stream, state) {
|
||||
var escaped = false, next, end = false;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (next == quote && !escaped){
|
||||
var afterNext = stream.peek();
|
||||
//look if the character if the quote is like the B in '10100010'B
|
||||
if (afterNext){
|
||||
afterNext = afterNext.toLowerCase();
|
||||
if(afterNext == "b" || afterNext == "h" || afterNext == "o")
|
||||
stream.next();
|
||||
}
|
||||
end = true; break;
|
||||
}
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
if (end || !(escaped || multiLineStrings))
|
||||
state.tokenize = null;
|
||||
return "string";
|
||||
};
|
||||
}
|
||||
|
||||
function Context(indented, column, type, align, prev) {
|
||||
this.indented = indented;
|
||||
this.column = column;
|
||||
this.type = type;
|
||||
this.align = align;
|
||||
this.prev = prev;
|
||||
}
|
||||
function pushContext(state, col, type) {
|
||||
var indent = state.indented;
|
||||
if (state.context && state.context.type == "statement")
|
||||
indent = state.context.indented;
|
||||
return state.context = new Context(indent, col, type, null, state.context);
|
||||
}
|
||||
function popContext(state) {
|
||||
var t = state.context.type;
|
||||
if (t == ")" || t == "]" || t == "}")
|
||||
state.indented = state.context.indented;
|
||||
return state.context = state.context.prev;
|
||||
}
|
||||
|
||||
//Interface
|
||||
return {
|
||||
startState: function(basecolumn) {
|
||||
return {
|
||||
tokenize: null,
|
||||
context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
|
||||
indented: 0,
|
||||
startOfLine: true
|
||||
};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
var ctx = state.context;
|
||||
if (stream.sol()) {
|
||||
if (ctx.align == null) ctx.align = false;
|
||||
state.indented = stream.indentation();
|
||||
state.startOfLine = true;
|
||||
}
|
||||
if (stream.eatSpace()) return null;
|
||||
curPunc = null;
|
||||
var style = (state.tokenize || tokenBase)(stream, state);
|
||||
if (style == "comment") return style;
|
||||
if (ctx.align == null) ctx.align = true;
|
||||
|
||||
if ((curPunc == ";" || curPunc == ":" || curPunc == ",")
|
||||
&& ctx.type == "statement"){
|
||||
popContext(state);
|
||||
}
|
||||
else if (curPunc == "{") pushContext(state, stream.column(), "}");
|
||||
else if (curPunc == "[") pushContext(state, stream.column(), "]");
|
||||
else if (curPunc == "(") pushContext(state, stream.column(), ")");
|
||||
else if (curPunc == "}") {
|
||||
while (ctx.type == "statement") ctx = popContext(state);
|
||||
if (ctx.type == "}") ctx = popContext(state);
|
||||
while (ctx.type == "statement") ctx = popContext(state);
|
||||
}
|
||||
else if (curPunc == ctx.type) popContext(state);
|
||||
else if (indentStatements && (((ctx.type == "}" || ctx.type == "top")
|
||||
&& curPunc != ';') || (ctx.type == "statement"
|
||||
&& curPunc == "newstatement")))
|
||||
pushContext(state, stream.column(), "statement");
|
||||
|
||||
state.startOfLine = false;
|
||||
return style;
|
||||
},
|
||||
|
||||
electricChars: "{}",
|
||||
lineComment: "--",
|
||||
fold: "brace"
|
||||
};
|
||||
});
|
||||
|
||||
function words(str) {
|
||||
var obj = {}, words = str.split(" ");
|
||||
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
|
||||
return obj;
|
||||
}
|
||||
|
||||
CodeMirror.defineMIME("text/x-ttcn-asn", {
|
||||
name: "asn.1",
|
||||
keywords: words("DEFINITIONS OBJECTS IF DERIVED INFORMATION ACTION" +
|
||||
" REPLY ANY NAMED CHARACTERIZED BEHAVIOUR REGISTERED" +
|
||||
" WITH AS IDENTIFIED CONSTRAINED BY PRESENT BEGIN" +
|
||||
" IMPORTS FROM UNITS SYNTAX MIN-ACCESS MAX-ACCESS" +
|
||||
" MINACCESS MAXACCESS REVISION STATUS DESCRIPTION" +
|
||||
" SEQUENCE SET COMPONENTS OF CHOICE DistinguishedName" +
|
||||
" ENUMERATED SIZE MODULE END INDEX AUGMENTS EXTENSIBILITY" +
|
||||
" IMPLIED EXPORTS"),
|
||||
cmipVerbs: words("ACTIONS ADD GET NOTIFICATIONS REPLACE REMOVE"),
|
||||
compareTypes: words("OPTIONAL DEFAULT MANAGED MODULE-TYPE MODULE_IDENTITY" +
|
||||
" MODULE-COMPLIANCE OBJECT-TYPE OBJECT-IDENTITY" +
|
||||
" OBJECT-COMPLIANCE MODE CONFIRMED CONDITIONAL" +
|
||||
" SUBORDINATE SUPERIOR CLASS TRUE FALSE NULL" +
|
||||
" TEXTUAL-CONVENTION"),
|
||||
status: words("current deprecated mandatory obsolete"),
|
||||
tags: words("APPLICATION AUTOMATIC EXPLICIT IMPLICIT PRIVATE TAGS" +
|
||||
" UNIVERSAL"),
|
||||
storage: words("BOOLEAN INTEGER OBJECT IDENTIFIER BIT OCTET STRING" +
|
||||
" UTCTime InterfaceIndex IANAifType CMIP-Attribute" +
|
||||
" REAL PACKAGE PACKAGES IpAddress PhysAddress" +
|
||||
" NetworkAddress BITS BMPString TimeStamp TimeTicks" +
|
||||
" TruthValue RowStatus DisplayString GeneralString" +
|
||||
" GraphicString IA5String NumericString" +
|
||||
" PrintableString SnmpAdminString TeletexString" +
|
||||
" UTF8String VideotexString VisibleString StringStore" +
|
||||
" ISO646String T61String UniversalString Unsigned32" +
|
||||
" Integer32 Gauge Gauge32 Counter Counter32 Counter64"),
|
||||
modifier: words("ATTRIBUTE ATTRIBUTES MANDATORY-GROUP MANDATORY-GROUPS" +
|
||||
" GROUP GROUPS ELEMENTS EQUALITY ORDERING SUBSTRINGS" +
|
||||
" DEFINED"),
|
||||
accessTypes: words("not-accessible accessible-for-notify read-only" +
|
||||
" read-create read-write"),
|
||||
multiLineStrings: true
|
||||
});
|
||||
});
|
||||
220
libraries/codemirror/mode/asterisk/asterisk.js
vendored
@@ -1,220 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: mode/asterisk/asterisk.js
|
||||
*
|
||||
* Description: CodeMirror mode for Asterisk dialplan
|
||||
*
|
||||
* Created: 05/17/2012 09:20:25 PM
|
||||
* Revision: 08/05/2019 AstLinux Project: Support block-comments
|
||||
*
|
||||
* Author: Stas Kobzar (stas@modulis.ca),
|
||||
* Company: Modulis.ca Inc.
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineMode("asterisk", function() {
|
||||
var atoms = ["exten", "same", "include","ignorepat","switch"],
|
||||
dpcmd = ["#include","#exec"],
|
||||
apps = [
|
||||
"addqueuemember","adsiprog","aelsub","agentlogin","agentmonitoroutgoing","agi",
|
||||
"alarmreceiver","amd","answer","authenticate","background","backgrounddetect",
|
||||
"bridge","busy","callcompletioncancel","callcompletionrequest","celgenuserevent",
|
||||
"changemonitor","chanisavail","channelredirect","chanspy","clearhash","confbridge",
|
||||
"congestion","continuewhile","controlplayback","dahdiacceptr2call","dahdibarge",
|
||||
"dahdiras","dahdiscan","dahdisendcallreroutingfacility","dahdisendkeypadfacility",
|
||||
"datetime","dbdel","dbdeltree","deadagi","dial","dictate","directory","disa",
|
||||
"dumpchan","eagi","echo","endwhile","exec","execif","execiftime","exitwhile","extenspy",
|
||||
"externalivr","festival","flash","followme","forkcdr","getcpeid","gosub","gosubif",
|
||||
"goto","gotoif","gotoiftime","hangup","iax2provision","ices","importvar","incomplete",
|
||||
"ivrdemo","jabberjoin","jabberleave","jabbersend","jabbersendgroup","jabberstatus",
|
||||
"jack","log","macro","macroexclusive","macroexit","macroif","mailboxexists","meetme",
|
||||
"meetmeadmin","meetmechanneladmin","meetmecount","milliwatt","minivmaccmess","minivmdelete",
|
||||
"minivmgreet","minivmmwi","minivmnotify","minivmrecord","mixmonitor","monitor","morsecode",
|
||||
"mp3player","mset","musiconhold","nbscat","nocdr","noop","odbc","odbc","odbcfinish",
|
||||
"originate","ospauth","ospfinish","osplookup","ospnext","page","park","parkandannounce",
|
||||
"parkedcall","pausemonitor","pausequeuemember","pickup","pickupchan","playback","playtones",
|
||||
"privacymanager","proceeding","progress","queue","queuelog","raiseexception","read","readexten",
|
||||
"readfile","receivefax","receivefax","receivefax","record","removequeuemember",
|
||||
"resetcdr","retrydial","return","ringing","sayalpha","saycountedadj","saycountednoun",
|
||||
"saycountpl","saydigits","saynumber","sayphonetic","sayunixtime","senddtmf","sendfax",
|
||||
"sendfax","sendfax","sendimage","sendtext","sendurl","set","setamaflags",
|
||||
"setcallerpres","setmusiconhold","sipaddheader","sipdtmfmode","sipremoveheader","skel",
|
||||
"slastation","slatrunk","sms","softhangup","speechactivategrammar","speechbackground",
|
||||
"speechcreate","speechdeactivategrammar","speechdestroy","speechloadgrammar","speechprocessingsound",
|
||||
"speechstart","speechunloadgrammar","stackpop","startmusiconhold","stopmixmonitor","stopmonitor",
|
||||
"stopmusiconhold","stopplaytones","system","testclient","testserver","transfer","tryexec",
|
||||
"trysystem","unpausemonitor","unpausequeuemember","userevent","verbose","vmauthenticate",
|
||||
"vmsayname","voicemail","voicemailmain","wait","waitexten","waitfornoise","waitforring",
|
||||
"waitforsilence","waitmusiconhold","waituntil","while","zapateller"
|
||||
];
|
||||
|
||||
function basicToken(stream,state){
|
||||
var cur = '';
|
||||
var ch = stream.next();
|
||||
// comment
|
||||
if (state.blockComment) {
|
||||
if (ch == "-" && stream.match("-;", true)) {
|
||||
state.blockComment = false;
|
||||
} else if (stream.skipTo("--;")) {
|
||||
stream.next();
|
||||
stream.next();
|
||||
stream.next();
|
||||
state.blockComment = false;
|
||||
} else {
|
||||
stream.skipToEnd();
|
||||
}
|
||||
return "comment";
|
||||
}
|
||||
if(ch == ";") {
|
||||
if (stream.match("--", true)) {
|
||||
if (!stream.match("-", false)) { // Except ;--- is not a block comment
|
||||
state.blockComment = true;
|
||||
return "comment";
|
||||
}
|
||||
}
|
||||
stream.skipToEnd();
|
||||
return "comment";
|
||||
}
|
||||
// context
|
||||
if(ch == '[') {
|
||||
stream.skipTo(']');
|
||||
stream.eat(']');
|
||||
return "header";
|
||||
}
|
||||
// string
|
||||
if(ch == '"') {
|
||||
stream.skipTo('"');
|
||||
return "string";
|
||||
}
|
||||
if(ch == "'") {
|
||||
stream.skipTo("'");
|
||||
return "string-2";
|
||||
}
|
||||
// dialplan commands
|
||||
if(ch == '#') {
|
||||
stream.eatWhile(/\w/);
|
||||
cur = stream.current();
|
||||
if(dpcmd.indexOf(cur) !== -1) {
|
||||
stream.skipToEnd();
|
||||
return "strong";
|
||||
}
|
||||
}
|
||||
// application args
|
||||
if(ch == '$'){
|
||||
var ch1 = stream.peek();
|
||||
if(ch1 == '{'){
|
||||
stream.skipTo('}');
|
||||
stream.eat('}');
|
||||
return "variable-3";
|
||||
}
|
||||
}
|
||||
// extension
|
||||
stream.eatWhile(/\w/);
|
||||
cur = stream.current();
|
||||
if(atoms.indexOf(cur) !== -1) {
|
||||
state.extenStart = true;
|
||||
switch(cur) {
|
||||
case 'same': state.extenSame = true; break;
|
||||
case 'include':
|
||||
case 'switch':
|
||||
case 'ignorepat':
|
||||
state.extenInclude = true;break;
|
||||
default:break;
|
||||
}
|
||||
return "atom";
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function() {
|
||||
return {
|
||||
blockComment: false,
|
||||
extenStart: false,
|
||||
extenSame: false,
|
||||
extenInclude: false,
|
||||
extenExten: false,
|
||||
extenPriority: false,
|
||||
extenApplication: false
|
||||
};
|
||||
},
|
||||
token: function(stream, state) {
|
||||
|
||||
var cur = '';
|
||||
if(stream.eatSpace()) return null;
|
||||
// extension started
|
||||
if(state.extenStart){
|
||||
stream.eatWhile(/[^\s]/);
|
||||
cur = stream.current();
|
||||
if(/^=>?$/.test(cur)){
|
||||
state.extenExten = true;
|
||||
state.extenStart = false;
|
||||
return "strong";
|
||||
} else {
|
||||
state.extenStart = false;
|
||||
stream.skipToEnd();
|
||||
return "error";
|
||||
}
|
||||
} else if(state.extenExten) {
|
||||
// set exten and priority
|
||||
state.extenExten = false;
|
||||
state.extenPriority = true;
|
||||
stream.eatWhile(/[^,]/);
|
||||
if(state.extenInclude) {
|
||||
stream.skipToEnd();
|
||||
state.extenPriority = false;
|
||||
state.extenInclude = false;
|
||||
}
|
||||
if(state.extenSame) {
|
||||
state.extenPriority = false;
|
||||
state.extenSame = false;
|
||||
state.extenApplication = true;
|
||||
}
|
||||
return "tag";
|
||||
} else if(state.extenPriority) {
|
||||
state.extenPriority = false;
|
||||
state.extenApplication = true;
|
||||
stream.next(); // get comma
|
||||
if(state.extenSame) return null;
|
||||
stream.eatWhile(/[^,]/);
|
||||
return "number";
|
||||
} else if(state.extenApplication) {
|
||||
stream.eatWhile(/,/);
|
||||
cur = stream.current();
|
||||
if(cur === ',') return null;
|
||||
stream.eatWhile(/\w/);
|
||||
cur = stream.current().toLowerCase();
|
||||
state.extenApplication = false;
|
||||
if(apps.indexOf(cur) !== -1){
|
||||
return "def strong";
|
||||
}
|
||||
} else{
|
||||
return basicToken(stream,state);
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
blockCommentStart: ";--",
|
||||
blockCommentEnd: "--;",
|
||||
lineComment: ";"
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/x-asterisk", "asterisk");
|
||||
|
||||
});
|
||||
85
libraries/codemirror/mode/brainfuck/brainfuck.js
vendored
@@ -1,85 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
// Brainfuck mode created by Michael Kaminsky https://github.com/mkaminsky11
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object")
|
||||
mod(require("../../lib/codemirror"))
|
||||
else if (typeof define == "function" && define.amd)
|
||||
define(["../../lib/codemirror"], mod)
|
||||
else
|
||||
mod(CodeMirror)
|
||||
})(function(CodeMirror) {
|
||||
"use strict"
|
||||
var reserve = "><+-.,[]".split("");
|
||||
/*
|
||||
comments can be either:
|
||||
placed behind lines
|
||||
|
||||
+++ this is a comment
|
||||
|
||||
where reserved characters cannot be used
|
||||
or in a loop
|
||||
[
|
||||
this is ok to use [ ] and stuff
|
||||
]
|
||||
or preceded by #
|
||||
*/
|
||||
CodeMirror.defineMode("brainfuck", function() {
|
||||
return {
|
||||
startState: function() {
|
||||
return {
|
||||
commentLine: false,
|
||||
left: 0,
|
||||
right: 0,
|
||||
commentLoop: false
|
||||
}
|
||||
},
|
||||
token: function(stream, state) {
|
||||
if (stream.eatSpace()) return null
|
||||
if(stream.sol()){
|
||||
state.commentLine = false;
|
||||
}
|
||||
var ch = stream.next().toString();
|
||||
if(reserve.indexOf(ch) !== -1){
|
||||
if(state.commentLine === true){
|
||||
if(stream.eol()){
|
||||
state.commentLine = false;
|
||||
}
|
||||
return "comment";
|
||||
}
|
||||
if(ch === "]" || ch === "["){
|
||||
if(ch === "["){
|
||||
state.left++;
|
||||
}
|
||||
else{
|
||||
state.right++;
|
||||
}
|
||||
return "bracket";
|
||||
}
|
||||
else if(ch === "+" || ch === "-"){
|
||||
return "keyword";
|
||||
}
|
||||
else if(ch === "<" || ch === ">"){
|
||||
return "atom";
|
||||
}
|
||||
else if(ch === "." || ch === ","){
|
||||
return "def";
|
||||
}
|
||||
}
|
||||
else{
|
||||
state.commentLine = true;
|
||||
if(stream.eol()){
|
||||
state.commentLine = false;
|
||||
}
|
||||
return "comment";
|
||||
}
|
||||
if(stream.eol()){
|
||||
state.commentLine = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
CodeMirror.defineMIME("text/x-brainfuck","brainfuck")
|
||||
});
|
||||
942
libraries/codemirror/mode/clike/clike.js
vendored
@@ -1,942 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
function Context(indented, column, type, info, align, prev) {
|
||||
this.indented = indented;
|
||||
this.column = column;
|
||||
this.type = type;
|
||||
this.info = info;
|
||||
this.align = align;
|
||||
this.prev = prev;
|
||||
}
|
||||
function pushContext(state, col, type, info) {
|
||||
var indent = state.indented;
|
||||
if (state.context && state.context.type == "statement" && type != "statement")
|
||||
indent = state.context.indented;
|
||||
return state.context = new Context(indent, col, type, info, null, state.context);
|
||||
}
|
||||
function popContext(state) {
|
||||
var t = state.context.type;
|
||||
if (t == ")" || t == "]" || t == "}")
|
||||
state.indented = state.context.indented;
|
||||
return state.context = state.context.prev;
|
||||
}
|
||||
|
||||
function typeBefore(stream, state, pos) {
|
||||
if (state.prevToken == "variable" || state.prevToken == "type") return true;
|
||||
if (/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(stream.string.slice(0, pos))) return true;
|
||||
if (state.typeAtEndOfLine && stream.column() == stream.indentation()) return true;
|
||||
}
|
||||
|
||||
function isTopScope(context) {
|
||||
for (;;) {
|
||||
if (!context || context.type == "top") return true;
|
||||
if (context.type == "}" && context.prev.info != "namespace") return false;
|
||||
context = context.prev;
|
||||
}
|
||||
}
|
||||
|
||||
CodeMirror.defineMode("clike", function(config, parserConfig) {
|
||||
var indentUnit = config.indentUnit,
|
||||
statementIndentUnit = parserConfig.statementIndentUnit || indentUnit,
|
||||
dontAlignCalls = parserConfig.dontAlignCalls,
|
||||
keywords = parserConfig.keywords || {},
|
||||
types = parserConfig.types || {},
|
||||
builtin = parserConfig.builtin || {},
|
||||
blockKeywords = parserConfig.blockKeywords || {},
|
||||
defKeywords = parserConfig.defKeywords || {},
|
||||
atoms = parserConfig.atoms || {},
|
||||
hooks = parserConfig.hooks || {},
|
||||
multiLineStrings = parserConfig.multiLineStrings,
|
||||
indentStatements = parserConfig.indentStatements !== false,
|
||||
indentSwitch = parserConfig.indentSwitch !== false,
|
||||
namespaceSeparator = parserConfig.namespaceSeparator,
|
||||
isPunctuationChar = parserConfig.isPunctuationChar || /[\[\]{}\(\),;\:\.]/,
|
||||
numberStart = parserConfig.numberStart || /[\d\.]/,
|
||||
number = parserConfig.number || /^(?:0x[a-f\d]+|0b[01]+|(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)(u|ll?|l|f)?/i,
|
||||
isOperatorChar = parserConfig.isOperatorChar || /[+\-*&%=<>!?|\/]/,
|
||||
isIdentifierChar = parserConfig.isIdentifierChar || /[\w\$_\xa1-\uffff]/,
|
||||
// An optional function that takes a {string} token and returns true if it
|
||||
// should be treated as a builtin.
|
||||
isReservedIdentifier = parserConfig.isReservedIdentifier || false;
|
||||
|
||||
var curPunc, isDefKeyword;
|
||||
|
||||
function tokenBase(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (hooks[ch]) {
|
||||
var result = hooks[ch](stream, state);
|
||||
if (result !== false) return result;
|
||||
}
|
||||
if (ch == '"' || ch == "'") {
|
||||
state.tokenize = tokenString(ch);
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
if (numberStart.test(ch)) {
|
||||
stream.backUp(1)
|
||||
if (stream.match(number)) return "number"
|
||||
stream.next()
|
||||
}
|
||||
if (isPunctuationChar.test(ch)) {
|
||||
curPunc = ch;
|
||||
return null;
|
||||
}
|
||||
if (ch == "/") {
|
||||
if (stream.eat("*")) {
|
||||
state.tokenize = tokenComment;
|
||||
return tokenComment(stream, state);
|
||||
}
|
||||
if (stream.eat("/")) {
|
||||
stream.skipToEnd();
|
||||
return "comment";
|
||||
}
|
||||
}
|
||||
if (isOperatorChar.test(ch)) {
|
||||
while (!stream.match(/^\/[\/*]/, false) && stream.eat(isOperatorChar)) {}
|
||||
return "operator";
|
||||
}
|
||||
stream.eatWhile(isIdentifierChar);
|
||||
if (namespaceSeparator) while (stream.match(namespaceSeparator))
|
||||
stream.eatWhile(isIdentifierChar);
|
||||
|
||||
var cur = stream.current();
|
||||
if (contains(keywords, cur)) {
|
||||
if (contains(blockKeywords, cur)) curPunc = "newstatement";
|
||||
if (contains(defKeywords, cur)) isDefKeyword = true;
|
||||
return "keyword";
|
||||
}
|
||||
if (contains(types, cur)) return "type";
|
||||
if (contains(builtin, cur)
|
||||
|| (isReservedIdentifier && isReservedIdentifier(cur))) {
|
||||
if (contains(blockKeywords, cur)) curPunc = "newstatement";
|
||||
return "builtin";
|
||||
}
|
||||
if (contains(atoms, cur)) return "atom";
|
||||
return "variable";
|
||||
}
|
||||
|
||||
function tokenString(quote) {
|
||||
return function(stream, state) {
|
||||
var escaped = false, next, end = false;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (next == quote && !escaped) {end = true; break;}
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
if (end || !(escaped || multiLineStrings))
|
||||
state.tokenize = null;
|
||||
return "string";
|
||||
};
|
||||
}
|
||||
|
||||
function tokenComment(stream, state) {
|
||||
var maybeEnd = false, ch;
|
||||
while (ch = stream.next()) {
|
||||
if (ch == "/" && maybeEnd) {
|
||||
state.tokenize = null;
|
||||
break;
|
||||
}
|
||||
maybeEnd = (ch == "*");
|
||||
}
|
||||
return "comment";
|
||||
}
|
||||
|
||||
function maybeEOL(stream, state) {
|
||||
if (parserConfig.typeFirstDefinitions && stream.eol() && isTopScope(state.context))
|
||||
state.typeAtEndOfLine = typeBefore(stream, state, stream.pos)
|
||||
}
|
||||
|
||||
// Interface
|
||||
|
||||
return {
|
||||
startState: function(basecolumn) {
|
||||
return {
|
||||
tokenize: null,
|
||||
context: new Context((basecolumn || 0) - indentUnit, 0, "top", null, false),
|
||||
indented: 0,
|
||||
startOfLine: true,
|
||||
prevToken: null
|
||||
};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
var ctx = state.context;
|
||||
if (stream.sol()) {
|
||||
if (ctx.align == null) ctx.align = false;
|
||||
state.indented = stream.indentation();
|
||||
state.startOfLine = true;
|
||||
}
|
||||
if (stream.eatSpace()) { maybeEOL(stream, state); return null; }
|
||||
curPunc = isDefKeyword = null;
|
||||
var style = (state.tokenize || tokenBase)(stream, state);
|
||||
if (style == "comment" || style == "meta") return style;
|
||||
if (ctx.align == null) ctx.align = true;
|
||||
|
||||
if (curPunc == ";" || curPunc == ":" || (curPunc == "," && stream.match(/^\s*(?:\/\/.*)?$/, false)))
|
||||
while (state.context.type == "statement") popContext(state);
|
||||
else if (curPunc == "{") pushContext(state, stream.column(), "}");
|
||||
else if (curPunc == "[") pushContext(state, stream.column(), "]");
|
||||
else if (curPunc == "(") pushContext(state, stream.column(), ")");
|
||||
else if (curPunc == "}") {
|
||||
while (ctx.type == "statement") ctx = popContext(state);
|
||||
if (ctx.type == "}") ctx = popContext(state);
|
||||
while (ctx.type == "statement") ctx = popContext(state);
|
||||
}
|
||||
else if (curPunc == ctx.type) popContext(state);
|
||||
else if (indentStatements &&
|
||||
(((ctx.type == "}" || ctx.type == "top") && curPunc != ";") ||
|
||||
(ctx.type == "statement" && curPunc == "newstatement"))) {
|
||||
pushContext(state, stream.column(), "statement", stream.current());
|
||||
}
|
||||
|
||||
if (style == "variable" &&
|
||||
((state.prevToken == "def" ||
|
||||
(parserConfig.typeFirstDefinitions && typeBefore(stream, state, stream.start) &&
|
||||
isTopScope(state.context) && stream.match(/^\s*\(/, false)))))
|
||||
style = "def";
|
||||
|
||||
if (hooks.token) {
|
||||
var result = hooks.token(stream, state, style);
|
||||
if (result !== undefined) style = result;
|
||||
}
|
||||
|
||||
if (style == "def" && parserConfig.styleDefs === false) style = "variable";
|
||||
|
||||
state.startOfLine = false;
|
||||
state.prevToken = isDefKeyword ? "def" : style || curPunc;
|
||||
maybeEOL(stream, state);
|
||||
return style;
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
if (state.tokenize != tokenBase && state.tokenize != null || state.typeAtEndOfLine && isTopScope(state.context))
|
||||
return CodeMirror.Pass;
|
||||
var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
|
||||
var closing = firstChar == ctx.type;
|
||||
if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev;
|
||||
if (parserConfig.dontIndentStatements)
|
||||
while (ctx.type == "statement" && parserConfig.dontIndentStatements.test(ctx.info))
|
||||
ctx = ctx.prev
|
||||
if (hooks.indent) {
|
||||
var hook = hooks.indent(state, ctx, textAfter, indentUnit);
|
||||
if (typeof hook == "number") return hook
|
||||
}
|
||||
var switchBlock = ctx.prev && ctx.prev.info == "switch";
|
||||
if (parserConfig.allmanIndentation && /[{(]/.test(firstChar)) {
|
||||
while (ctx.type != "top" && ctx.type != "}") ctx = ctx.prev
|
||||
return ctx.indented
|
||||
}
|
||||
if (ctx.type == "statement")
|
||||
return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit);
|
||||
if (ctx.align && (!dontAlignCalls || ctx.type != ")"))
|
||||
return ctx.column + (closing ? 0 : 1);
|
||||
if (ctx.type == ")" && !closing)
|
||||
return ctx.indented + statementIndentUnit;
|
||||
|
||||
return ctx.indented + (closing ? 0 : indentUnit) +
|
||||
(!closing && switchBlock && !/^(?:case|default)\b/.test(textAfter) ? indentUnit : 0);
|
||||
},
|
||||
|
||||
electricInput: indentSwitch ? /^\s*(?:case .*?:|default:|\{\}?|\})$/ : /^\s*[{}]$/,
|
||||
blockCommentStart: "/*",
|
||||
blockCommentEnd: "*/",
|
||||
blockCommentContinue: " * ",
|
||||
lineComment: "//",
|
||||
fold: "brace"
|
||||
};
|
||||
});
|
||||
|
||||
function words(str) {
|
||||
var obj = {}, words = str.split(" ");
|
||||
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
|
||||
return obj;
|
||||
}
|
||||
function contains(words, word) {
|
||||
if (typeof words === "function") {
|
||||
return words(word);
|
||||
} else {
|
||||
return words.propertyIsEnumerable(word);
|
||||
}
|
||||
}
|
||||
var cKeywords = "auto if break case register continue return default do sizeof " +
|
||||
"static else struct switch extern typedef union for goto while enum const " +
|
||||
"volatile inline restrict asm fortran";
|
||||
|
||||
// Keywords from https://en.cppreference.com/w/cpp/keyword includes C++20.
|
||||
var cppKeywords = "alignas alignof and and_eq audit axiom bitand bitor catch " +
|
||||
"class compl concept constexpr const_cast decltype delete dynamic_cast " +
|
||||
"explicit export final friend import module mutable namespace new noexcept " +
|
||||
"not not_eq operator or or_eq override private protected public " +
|
||||
"reinterpret_cast requires static_assert static_cast template this " +
|
||||
"thread_local throw try typeid typename using virtual xor xor_eq";
|
||||
|
||||
var objCKeywords = "bycopy byref in inout oneway out self super atomic nonatomic retain copy " +
|
||||
"readwrite readonly strong weak assign typeof nullable nonnull null_resettable _cmd " +
|
||||
"@interface @implementation @end @protocol @encode @property @synthesize @dynamic @class " +
|
||||
"@public @package @private @protected @required @optional @try @catch @finally @import " +
|
||||
"@selector @encode @defs @synchronized @autoreleasepool @compatibility_alias @available";
|
||||
|
||||
var objCBuiltins = "FOUNDATION_EXPORT FOUNDATION_EXTERN NS_INLINE NS_FORMAT_FUNCTION " +
|
||||
" NS_RETURNS_RETAINEDNS_ERROR_ENUM NS_RETURNS_NOT_RETAINED NS_RETURNS_INNER_POINTER " +
|
||||
"NS_DESIGNATED_INITIALIZER NS_ENUM NS_OPTIONS NS_REQUIRES_NIL_TERMINATION " +
|
||||
"NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END NS_SWIFT_NAME NS_REFINED_FOR_SWIFT"
|
||||
|
||||
// Do not use this. Use the cTypes function below. This is global just to avoid
|
||||
// excessive calls when cTypes is being called multiple times during a parse.
|
||||
var basicCTypes = words("int long char short double float unsigned signed " +
|
||||
"void bool");
|
||||
|
||||
// Do not use this. Use the objCTypes function below. This is global just to avoid
|
||||
// excessive calls when objCTypes is being called multiple times during a parse.
|
||||
var basicObjCTypes = words("SEL instancetype id Class Protocol BOOL");
|
||||
|
||||
// Returns true if identifier is a "C" type.
|
||||
// C type is defined as those that are reserved by the compiler (basicTypes),
|
||||
// and those that end in _t (Reserved by POSIX for types)
|
||||
// http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html
|
||||
function cTypes(identifier) {
|
||||
return contains(basicCTypes, identifier) || /.+_t$/.test(identifier);
|
||||
}
|
||||
|
||||
// Returns true if identifier is a "Objective C" type.
|
||||
function objCTypes(identifier) {
|
||||
return cTypes(identifier) || contains(basicObjCTypes, identifier);
|
||||
}
|
||||
|
||||
var cBlockKeywords = "case do else for if switch while struct enum union";
|
||||
var cDefKeywords = "struct enum union";
|
||||
|
||||
function cppHook(stream, state) {
|
||||
if (!state.startOfLine) return false
|
||||
for (var ch, next = null; ch = stream.peek();) {
|
||||
if (ch == "\\" && stream.match(/^.$/)) {
|
||||
next = cppHook
|
||||
break
|
||||
} else if (ch == "/" && stream.match(/^\/[\/\*]/, false)) {
|
||||
break
|
||||
}
|
||||
stream.next()
|
||||
}
|
||||
state.tokenize = next
|
||||
return "meta"
|
||||
}
|
||||
|
||||
function pointerHook(_stream, state) {
|
||||
if (state.prevToken == "type") return "type";
|
||||
return false;
|
||||
}
|
||||
|
||||
// For C and C++ (and ObjC): identifiers starting with __
|
||||
// or _ followed by a capital letter are reserved for the compiler.
|
||||
function cIsReservedIdentifier(token) {
|
||||
if (!token || token.length < 2) return false;
|
||||
if (token[0] != '_') return false;
|
||||
return (token[1] == '_') || (token[1] !== token[1].toLowerCase());
|
||||
}
|
||||
|
||||
function cpp14Literal(stream) {
|
||||
stream.eatWhile(/[\w\.']/);
|
||||
return "number";
|
||||
}
|
||||
|
||||
function cpp11StringHook(stream, state) {
|
||||
stream.backUp(1);
|
||||
// Raw strings.
|
||||
if (stream.match(/^(?:R|u8R|uR|UR|LR)/)) {
|
||||
var match = stream.match(/^"([^\s\\()]{0,16})\(/);
|
||||
if (!match) {
|
||||
return false;
|
||||
}
|
||||
state.cpp11RawStringDelim = match[1];
|
||||
state.tokenize = tokenRawString;
|
||||
return tokenRawString(stream, state);
|
||||
}
|
||||
// Unicode strings/chars.
|
||||
if (stream.match(/^(?:u8|u|U|L)/)) {
|
||||
if (stream.match(/^["']/, /* eat */ false)) {
|
||||
return "string";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Ignore this hook.
|
||||
stream.next();
|
||||
return false;
|
||||
}
|
||||
|
||||
function cppLooksLikeConstructor(word) {
|
||||
var lastTwo = /(\w+)::~?(\w+)$/.exec(word);
|
||||
return lastTwo && lastTwo[1] == lastTwo[2];
|
||||
}
|
||||
|
||||
// C#-style strings where "" escapes a quote.
|
||||
function tokenAtString(stream, state) {
|
||||
var next;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (next == '"' && !stream.eat('"')) {
|
||||
state.tokenize = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return "string";
|
||||
}
|
||||
|
||||
// C++11 raw string literal is <prefix>"<delim>( anything )<delim>", where
|
||||
// <delim> can be a string up to 16 characters long.
|
||||
function tokenRawString(stream, state) {
|
||||
// Escape characters that have special regex meanings.
|
||||
var delim = state.cpp11RawStringDelim.replace(/[^\w\s]/g, '\\$&');
|
||||
var match = stream.match(new RegExp(".*?\\)" + delim + '"'));
|
||||
if (match)
|
||||
state.tokenize = null;
|
||||
else
|
||||
stream.skipToEnd();
|
||||
return "string";
|
||||
}
|
||||
|
||||
function def(mimes, mode) {
|
||||
if (typeof mimes == "string") mimes = [mimes];
|
||||
var words = [];
|
||||
function add(obj) {
|
||||
if (obj) for (var prop in obj) if (obj.hasOwnProperty(prop))
|
||||
words.push(prop);
|
||||
}
|
||||
add(mode.keywords);
|
||||
add(mode.types);
|
||||
add(mode.builtin);
|
||||
add(mode.atoms);
|
||||
if (words.length) {
|
||||
mode.helperType = mimes[0];
|
||||
CodeMirror.registerHelper("hintWords", mimes[0], words);
|
||||
}
|
||||
|
||||
for (var i = 0; i < mimes.length; ++i)
|
||||
CodeMirror.defineMIME(mimes[i], mode);
|
||||
}
|
||||
|
||||
def(["text/x-csrc", "text/x-c", "text/x-chdr"], {
|
||||
name: "clike",
|
||||
keywords: words(cKeywords),
|
||||
types: cTypes,
|
||||
blockKeywords: words(cBlockKeywords),
|
||||
defKeywords: words(cDefKeywords),
|
||||
typeFirstDefinitions: true,
|
||||
atoms: words("NULL true false"),
|
||||
isReservedIdentifier: cIsReservedIdentifier,
|
||||
hooks: {
|
||||
"#": cppHook,
|
||||
"*": pointerHook,
|
||||
},
|
||||
modeProps: {fold: ["brace", "include"]}
|
||||
});
|
||||
|
||||
def(["text/x-c++src", "text/x-c++hdr"], {
|
||||
name: "clike",
|
||||
keywords: words(cKeywords + " " + cppKeywords),
|
||||
types: cTypes,
|
||||
blockKeywords: words(cBlockKeywords + " class try catch"),
|
||||
defKeywords: words(cDefKeywords + " class namespace"),
|
||||
typeFirstDefinitions: true,
|
||||
atoms: words("true false NULL nullptr"),
|
||||
dontIndentStatements: /^template$/,
|
||||
isIdentifierChar: /[\w\$_~\xa1-\uffff]/,
|
||||
isReservedIdentifier: cIsReservedIdentifier,
|
||||
hooks: {
|
||||
"#": cppHook,
|
||||
"*": pointerHook,
|
||||
"u": cpp11StringHook,
|
||||
"U": cpp11StringHook,
|
||||
"L": cpp11StringHook,
|
||||
"R": cpp11StringHook,
|
||||
"0": cpp14Literal,
|
||||
"1": cpp14Literal,
|
||||
"2": cpp14Literal,
|
||||
"3": cpp14Literal,
|
||||
"4": cpp14Literal,
|
||||
"5": cpp14Literal,
|
||||
"6": cpp14Literal,
|
||||
"7": cpp14Literal,
|
||||
"8": cpp14Literal,
|
||||
"9": cpp14Literal,
|
||||
token: function(stream, state, style) {
|
||||
if (style == "variable" && stream.peek() == "(" &&
|
||||
(state.prevToken == ";" || state.prevToken == null ||
|
||||
state.prevToken == "}") &&
|
||||
cppLooksLikeConstructor(stream.current()))
|
||||
return "def";
|
||||
}
|
||||
},
|
||||
namespaceSeparator: "::",
|
||||
modeProps: {fold: ["brace", "include"]}
|
||||
});
|
||||
|
||||
def("text/x-java", {
|
||||
name: "clike",
|
||||
keywords: words("abstract assert break case catch class const continue default " +
|
||||
"do else enum extends final finally for goto if implements import " +
|
||||
"instanceof interface native new package private protected public " +
|
||||
"return static strictfp super switch synchronized this throw throws transient " +
|
||||
"try volatile while @interface"),
|
||||
types: words("var byte short int long float double boolean char void Boolean Byte Character Double Float " +
|
||||
"Integer Long Number Object Short String StringBuffer StringBuilder Void"),
|
||||
blockKeywords: words("catch class do else finally for if switch try while"),
|
||||
defKeywords: words("class interface enum @interface"),
|
||||
typeFirstDefinitions: true,
|
||||
atoms: words("true false null"),
|
||||
number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+\.?\d*|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,
|
||||
hooks: {
|
||||
"@": function(stream) {
|
||||
// Don't match the @interface keyword.
|
||||
if (stream.match('interface', false)) return false;
|
||||
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
return "meta";
|
||||
},
|
||||
'"': function(stream, state) {
|
||||
if (!stream.match(/""$/)) return false;
|
||||
state.tokenize = tokenTripleString;
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
},
|
||||
modeProps: {fold: ["brace", "import"]}
|
||||
});
|
||||
|
||||
def("text/x-csharp", {
|
||||
name: "clike",
|
||||
keywords: words("abstract as async await base break case catch checked class const continue" +
|
||||
" default delegate do else enum event explicit extern finally fixed for" +
|
||||
" foreach goto if implicit in init interface internal is lock namespace new" +
|
||||
" operator out override params private protected public readonly record ref required return sealed" +
|
||||
" sizeof stackalloc static struct switch this throw try typeof unchecked" +
|
||||
" unsafe using virtual void volatile while add alias ascending descending dynamic from get" +
|
||||
" global group into join let orderby partial remove select set value var yield"),
|
||||
types: words("Action Boolean Byte Char DateTime DateTimeOffset Decimal Double Func" +
|
||||
" Guid Int16 Int32 Int64 Object SByte Single String Task TimeSpan UInt16 UInt32" +
|
||||
" UInt64 bool byte char decimal double short int long object" +
|
||||
" sbyte float string ushort uint ulong"),
|
||||
blockKeywords: words("catch class do else finally for foreach if struct switch try while"),
|
||||
defKeywords: words("class interface namespace record struct var"),
|
||||
typeFirstDefinitions: true,
|
||||
atoms: words("true false null"),
|
||||
hooks: {
|
||||
"@": function(stream, state) {
|
||||
if (stream.eat('"')) {
|
||||
state.tokenize = tokenAtString;
|
||||
return tokenAtString(stream, state);
|
||||
}
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
return "meta";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function tokenTripleString(stream, state) {
|
||||
var escaped = false;
|
||||
while (!stream.eol()) {
|
||||
if (!escaped && stream.match('"""')) {
|
||||
state.tokenize = null;
|
||||
break;
|
||||
}
|
||||
escaped = stream.next() == "\\" && !escaped;
|
||||
}
|
||||
return "string";
|
||||
}
|
||||
|
||||
function tokenNestedComment(depth) {
|
||||
return function (stream, state) {
|
||||
var ch
|
||||
while (ch = stream.next()) {
|
||||
if (ch == "*" && stream.eat("/")) {
|
||||
if (depth == 1) {
|
||||
state.tokenize = null
|
||||
break
|
||||
} else {
|
||||
state.tokenize = tokenNestedComment(depth - 1)
|
||||
return state.tokenize(stream, state)
|
||||
}
|
||||
} else if (ch == "/" && stream.eat("*")) {
|
||||
state.tokenize = tokenNestedComment(depth + 1)
|
||||
return state.tokenize(stream, state)
|
||||
}
|
||||
}
|
||||
return "comment"
|
||||
}
|
||||
}
|
||||
|
||||
def("text/x-scala", {
|
||||
name: "clike",
|
||||
keywords: words(
|
||||
/* scala */
|
||||
"abstract case catch class def do else extends final finally for forSome if " +
|
||||
"implicit import lazy match new null object override package private protected return " +
|
||||
"sealed super this throw trait try type val var while with yield _ " +
|
||||
|
||||
/* package scala */
|
||||
"assert assume require print println printf readLine readBoolean readByte readShort " +
|
||||
"readChar readInt readLong readFloat readDouble"
|
||||
),
|
||||
types: words(
|
||||
"AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " +
|
||||
"Enumeration Equiv Error Exception Fractional Function IndexedSeq Int Integral Iterable " +
|
||||
"Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " +
|
||||
"Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " +
|
||||
"StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector " +
|
||||
|
||||
/* package java.lang */
|
||||
"Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
|
||||
"Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
|
||||
"Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
|
||||
"StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"
|
||||
),
|
||||
multiLineStrings: true,
|
||||
blockKeywords: words("catch class enum do else finally for forSome if match switch try while"),
|
||||
defKeywords: words("class enum def object package trait type val var"),
|
||||
atoms: words("true false null"),
|
||||
indentStatements: false,
|
||||
indentSwitch: false,
|
||||
isOperatorChar: /[+\-*&%=<>!?|\/#:@]/,
|
||||
hooks: {
|
||||
"@": function(stream) {
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
return "meta";
|
||||
},
|
||||
'"': function(stream, state) {
|
||||
if (!stream.match('""')) return false;
|
||||
state.tokenize = tokenTripleString;
|
||||
return state.tokenize(stream, state);
|
||||
},
|
||||
"'": function(stream) {
|
||||
if (stream.match(/^(\\[^'\s]+|[^\\'])'/)) return "string-2"
|
||||
stream.eatWhile(/[\w\$_\xa1-\uffff]/);
|
||||
return "atom";
|
||||
},
|
||||
"=": function(stream, state) {
|
||||
var cx = state.context
|
||||
if (cx.type == "}" && cx.align && stream.eat(">")) {
|
||||
state.context = new Context(cx.indented, cx.column, cx.type, cx.info, null, cx.prev)
|
||||
return "operator"
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
|
||||
"/": function(stream, state) {
|
||||
if (!stream.eat("*")) return false
|
||||
state.tokenize = tokenNestedComment(1)
|
||||
return state.tokenize(stream, state)
|
||||
}
|
||||
},
|
||||
modeProps: {closeBrackets: {pairs: '()[]{}""', triples: '"'}}
|
||||
});
|
||||
|
||||
function tokenKotlinString(tripleString){
|
||||
return function (stream, state) {
|
||||
var escaped = false, next, end = false;
|
||||
while (!stream.eol()) {
|
||||
if (!tripleString && !escaped && stream.match('"') ) {end = true; break;}
|
||||
if (tripleString && stream.match('"""')) {end = true; break;}
|
||||
next = stream.next();
|
||||
if(!escaped && next == "$" && stream.match('{'))
|
||||
stream.skipTo("}");
|
||||
escaped = !escaped && next == "\\" && !tripleString;
|
||||
}
|
||||
if (end || !tripleString)
|
||||
state.tokenize = null;
|
||||
return "string";
|
||||
}
|
||||
}
|
||||
|
||||
def("text/x-kotlin", {
|
||||
name: "clike",
|
||||
keywords: words(
|
||||
/*keywords*/
|
||||
"package as typealias class interface this super val operator " +
|
||||
"var fun for is in This throw return annotation " +
|
||||
"break continue object if else while do try when !in !is as? " +
|
||||
|
||||
/*soft keywords*/
|
||||
"file import where by get set abstract enum open inner override private public internal " +
|
||||
"protected catch finally out final vararg reified dynamic companion constructor init " +
|
||||
"sealed field property receiver param sparam lateinit data inline noinline tailrec " +
|
||||
"external annotation crossinline const operator infix suspend actual expect setparam value"
|
||||
),
|
||||
types: words(
|
||||
/* package java.lang */
|
||||
"Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
|
||||
"Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
|
||||
"Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
|
||||
"StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void Annotation Any BooleanArray " +
|
||||
"ByteArray Char CharArray DeprecationLevel DoubleArray Enum FloatArray Function Int IntArray Lazy " +
|
||||
"LazyThreadSafetyMode LongArray Nothing ShortArray Unit"
|
||||
),
|
||||
intendSwitch: false,
|
||||
indentStatements: false,
|
||||
multiLineStrings: true,
|
||||
number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+(\.\d+)?|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,
|
||||
blockKeywords: words("catch class do else finally for if where try while enum"),
|
||||
defKeywords: words("class val var object interface fun"),
|
||||
atoms: words("true false null this"),
|
||||
hooks: {
|
||||
"@": function(stream) {
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
return "meta";
|
||||
},
|
||||
'*': function(_stream, state) {
|
||||
return state.prevToken == '.' ? 'variable' : 'operator';
|
||||
},
|
||||
'"': function(stream, state) {
|
||||
state.tokenize = tokenKotlinString(stream.match('""'));
|
||||
return state.tokenize(stream, state);
|
||||
},
|
||||
"/": function(stream, state) {
|
||||
if (!stream.eat("*")) return false;
|
||||
state.tokenize = tokenNestedComment(1);
|
||||
return state.tokenize(stream, state)
|
||||
},
|
||||
indent: function(state, ctx, textAfter, indentUnit) {
|
||||
var firstChar = textAfter && textAfter.charAt(0);
|
||||
if ((state.prevToken == "}" || state.prevToken == ")") && textAfter == "")
|
||||
return state.indented;
|
||||
if ((state.prevToken == "operator" && textAfter != "}" && state.context.type != "}") ||
|
||||
state.prevToken == "variable" && firstChar == "." ||
|
||||
(state.prevToken == "}" || state.prevToken == ")") && firstChar == ".")
|
||||
return indentUnit * 2 + ctx.indented;
|
||||
if (ctx.align && ctx.type == "}")
|
||||
return ctx.indented + (state.context.type == (textAfter || "").charAt(0) ? 0 : indentUnit);
|
||||
}
|
||||
},
|
||||
modeProps: {closeBrackets: {triples: '"'}}
|
||||
});
|
||||
|
||||
def(["x-shader/x-vertex", "x-shader/x-fragment"], {
|
||||
name: "clike",
|
||||
keywords: words("sampler1D sampler2D sampler3D samplerCube " +
|
||||
"sampler1DShadow sampler2DShadow " +
|
||||
"const attribute uniform varying " +
|
||||
"break continue discard return " +
|
||||
"for while do if else struct " +
|
||||
"in out inout"),
|
||||
types: words("float int bool void " +
|
||||
"vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 " +
|
||||
"mat2 mat3 mat4"),
|
||||
blockKeywords: words("for while do if else struct"),
|
||||
builtin: words("radians degrees sin cos tan asin acos atan " +
|
||||
"pow exp log exp2 sqrt inversesqrt " +
|
||||
"abs sign floor ceil fract mod min max clamp mix step smoothstep " +
|
||||
"length distance dot cross normalize ftransform faceforward " +
|
||||
"reflect refract matrixCompMult " +
|
||||
"lessThan lessThanEqual greaterThan greaterThanEqual " +
|
||||
"equal notEqual any all not " +
|
||||
"texture1D texture1DProj texture1DLod texture1DProjLod " +
|
||||
"texture2D texture2DProj texture2DLod texture2DProjLod " +
|
||||
"texture3D texture3DProj texture3DLod texture3DProjLod " +
|
||||
"textureCube textureCubeLod " +
|
||||
"shadow1D shadow2D shadow1DProj shadow2DProj " +
|
||||
"shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod " +
|
||||
"dFdx dFdy fwidth " +
|
||||
"noise1 noise2 noise3 noise4"),
|
||||
atoms: words("true false " +
|
||||
"gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex " +
|
||||
"gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 " +
|
||||
"gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 " +
|
||||
"gl_FogCoord gl_PointCoord " +
|
||||
"gl_Position gl_PointSize gl_ClipVertex " +
|
||||
"gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor " +
|
||||
"gl_TexCoord gl_FogFragCoord " +
|
||||
"gl_FragCoord gl_FrontFacing " +
|
||||
"gl_FragData gl_FragDepth " +
|
||||
"gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix " +
|
||||
"gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse " +
|
||||
"gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse " +
|
||||
"gl_TextureMatrixTranspose gl_ModelViewMatrixInverseTranspose " +
|
||||
"gl_ProjectionMatrixInverseTranspose " +
|
||||
"gl_ModelViewProjectionMatrixInverseTranspose " +
|
||||
"gl_TextureMatrixInverseTranspose " +
|
||||
"gl_NormalScale gl_DepthRange gl_ClipPlane " +
|
||||
"gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel " +
|
||||
"gl_FrontLightModelProduct gl_BackLightModelProduct " +
|
||||
"gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ " +
|
||||
"gl_FogParameters " +
|
||||
"gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords " +
|
||||
"gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats " +
|
||||
"gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits " +
|
||||
"gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits " +
|
||||
"gl_MaxDrawBuffers"),
|
||||
indentSwitch: false,
|
||||
hooks: {"#": cppHook},
|
||||
modeProps: {fold: ["brace", "include"]}
|
||||
});
|
||||
|
||||
def("text/x-nesc", {
|
||||
name: "clike",
|
||||
keywords: words(cKeywords + " as atomic async call command component components configuration event generic " +
|
||||
"implementation includes interface module new norace nx_struct nx_union post provides " +
|
||||
"signal task uses abstract extends"),
|
||||
types: cTypes,
|
||||
blockKeywords: words(cBlockKeywords),
|
||||
atoms: words("null true false"),
|
||||
hooks: {"#": cppHook},
|
||||
modeProps: {fold: ["brace", "include"]}
|
||||
});
|
||||
|
||||
def("text/x-objectivec", {
|
||||
name: "clike",
|
||||
keywords: words(cKeywords + " " + objCKeywords),
|
||||
types: objCTypes,
|
||||
builtin: words(objCBuiltins),
|
||||
blockKeywords: words(cBlockKeywords + " @synthesize @try @catch @finally @autoreleasepool @synchronized"),
|
||||
defKeywords: words(cDefKeywords + " @interface @implementation @protocol @class"),
|
||||
dontIndentStatements: /^@.*$/,
|
||||
typeFirstDefinitions: true,
|
||||
atoms: words("YES NO NULL Nil nil true false nullptr"),
|
||||
isReservedIdentifier: cIsReservedIdentifier,
|
||||
hooks: {
|
||||
"#": cppHook,
|
||||
"*": pointerHook,
|
||||
},
|
||||
modeProps: {fold: ["brace", "include"]}
|
||||
});
|
||||
|
||||
def("text/x-objectivec++", {
|
||||
name: "clike",
|
||||
keywords: words(cKeywords + " " + objCKeywords + " " + cppKeywords),
|
||||
types: objCTypes,
|
||||
builtin: words(objCBuiltins),
|
||||
blockKeywords: words(cBlockKeywords + " @synthesize @try @catch @finally @autoreleasepool @synchronized class try catch"),
|
||||
defKeywords: words(cDefKeywords + " @interface @implementation @protocol @class class namespace"),
|
||||
dontIndentStatements: /^@.*$|^template$/,
|
||||
typeFirstDefinitions: true,
|
||||
atoms: words("YES NO NULL Nil nil true false nullptr"),
|
||||
isReservedIdentifier: cIsReservedIdentifier,
|
||||
hooks: {
|
||||
"#": cppHook,
|
||||
"*": pointerHook,
|
||||
"u": cpp11StringHook,
|
||||
"U": cpp11StringHook,
|
||||
"L": cpp11StringHook,
|
||||
"R": cpp11StringHook,
|
||||
"0": cpp14Literal,
|
||||
"1": cpp14Literal,
|
||||
"2": cpp14Literal,
|
||||
"3": cpp14Literal,
|
||||
"4": cpp14Literal,
|
||||
"5": cpp14Literal,
|
||||
"6": cpp14Literal,
|
||||
"7": cpp14Literal,
|
||||
"8": cpp14Literal,
|
||||
"9": cpp14Literal,
|
||||
token: function(stream, state, style) {
|
||||
if (style == "variable" && stream.peek() == "(" &&
|
||||
(state.prevToken == ";" || state.prevToken == null ||
|
||||
state.prevToken == "}") &&
|
||||
cppLooksLikeConstructor(stream.current()))
|
||||
return "def";
|
||||
}
|
||||
},
|
||||
namespaceSeparator: "::",
|
||||
modeProps: {fold: ["brace", "include"]}
|
||||
});
|
||||
|
||||
def("text/x-squirrel", {
|
||||
name: "clike",
|
||||
keywords: words("base break clone continue const default delete enum extends function in class" +
|
||||
" foreach local resume return this throw typeof yield constructor instanceof static"),
|
||||
types: cTypes,
|
||||
blockKeywords: words("case catch class else for foreach if switch try while"),
|
||||
defKeywords: words("function local class"),
|
||||
typeFirstDefinitions: true,
|
||||
atoms: words("true false null"),
|
||||
hooks: {"#": cppHook},
|
||||
modeProps: {fold: ["brace", "include"]}
|
||||
});
|
||||
|
||||
// Ceylon Strings need to deal with interpolation
|
||||
var stringTokenizer = null;
|
||||
function tokenCeylonString(type) {
|
||||
return function(stream, state) {
|
||||
var escaped = false, next, end = false;
|
||||
while (!stream.eol()) {
|
||||
if (!escaped && stream.match('"') &&
|
||||
(type == "single" || stream.match('""'))) {
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
if (!escaped && stream.match('``')) {
|
||||
stringTokenizer = tokenCeylonString(type);
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
next = stream.next();
|
||||
escaped = type == "single" && !escaped && next == "\\";
|
||||
}
|
||||
if (end)
|
||||
state.tokenize = null;
|
||||
return "string";
|
||||
}
|
||||
}
|
||||
|
||||
def("text/x-ceylon", {
|
||||
name: "clike",
|
||||
keywords: words("abstracts alias assembly assert assign break case catch class continue dynamic else" +
|
||||
" exists extends finally for function given if import in interface is let module new" +
|
||||
" nonempty object of out outer package return satisfies super switch then this throw" +
|
||||
" try value void while"),
|
||||
types: function(word) {
|
||||
// In Ceylon all identifiers that start with an uppercase are types
|
||||
var first = word.charAt(0);
|
||||
return (first === first.toUpperCase() && first !== first.toLowerCase());
|
||||
},
|
||||
blockKeywords: words("case catch class dynamic else finally for function if interface module new object switch try while"),
|
||||
defKeywords: words("class dynamic function interface module object package value"),
|
||||
builtin: words("abstract actual aliased annotation by default deprecated doc final formal late license" +
|
||||
" native optional sealed see serializable shared suppressWarnings tagged throws variable"),
|
||||
isPunctuationChar: /[\[\]{}\(\),;\:\.`]/,
|
||||
isOperatorChar: /[+\-*&%=<>!?|^~:\/]/,
|
||||
numberStart: /[\d#$]/,
|
||||
number: /^(?:#[\da-fA-F_]+|\$[01_]+|[\d_]+[kMGTPmunpf]?|[\d_]+\.[\d_]+(?:[eE][-+]?\d+|[kMGTPmunpf]|)|)/i,
|
||||
multiLineStrings: true,
|
||||
typeFirstDefinitions: true,
|
||||
atoms: words("true false null larger smaller equal empty finished"),
|
||||
indentSwitch: false,
|
||||
styleDefs: false,
|
||||
hooks: {
|
||||
"@": function(stream) {
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
return "meta";
|
||||
},
|
||||
'"': function(stream, state) {
|
||||
state.tokenize = tokenCeylonString(stream.match('""') ? "triple" : "single");
|
||||
return state.tokenize(stream, state);
|
||||
},
|
||||
'`': function(stream, state) {
|
||||
if (!stringTokenizer || !stream.match('`')) return false;
|
||||
state.tokenize = stringTokenizer;
|
||||
stringTokenizer = null;
|
||||
return state.tokenize(stream, state);
|
||||
},
|
||||
"'": function(stream) {
|
||||
stream.eatWhile(/[\w\$_\xa1-\uffff]/);
|
||||
return "atom";
|
||||
},
|
||||
token: function(_stream, state, style) {
|
||||
if ((style == "variable" || style == "type") &&
|
||||
state.prevToken == ".") {
|
||||
return "variable-2";
|
||||
}
|
||||
}
|
||||
},
|
||||
modeProps: {
|
||||
fold: ["brace", "import"],
|
||||
closeBrackets: {triples: '"'}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||