@setoelkahfi / svara / commits / d733710

added codemirror editor

mellbacon committed May 15, 2023 at 18:33 UTC d733710aa1e617ecdea91de45b747ddcb6419e2e
9 files changed +280 -7
package.json
+1
@@ -13,6 +13,7 @@
13 },
14 "dependencies": {
15 "@tauri-apps/api": "^1.2.0",
16 + "codemirror": "^6.0.1",
17 "sass": "^1.62.0",
18 "sortablejs": "^1.15.0",
19 "svelte-splitpanes": "^0.7.13"
src/App.svelte
+11 -1
@@ -4,7 +4,7 @@
4 import { Pane, Splitpanes } from 'svelte-splitpanes';
5 import SidebarView from "./lib/SidebarView.svelte";
6 import Statusbar from "./lib/Statusbar.svelte";
7 - import EditorTabList from "./lib/EditorTabList.svelte";
7 + import EditorTabList, {hidden} from "./lib/EditorTabList.svelte";
8 import { onMount } from "svelte";
9 import { loadTheme } from "./config/themehandler";
10 import { appWindow } from '@tauri-apps/api/window';
@@ -68,6 +68,7 @@
68 <Pane>
69 <div id="container">
70 <EditorTabList />
71 + <div id="tabview" class:hidden={$hidden}></div>
72 </div>
73 </Pane>
74 </Splitpanes>
@@ -84,4 +85,13 @@
85 background-repeat: no-repeat;
86 background-position: center;
87 }
88 + #tabview {
89 + width: 100%;
90 + margin-left: 0.1rem;
91 + z-index: 1;
92 + position: absolute;
93 + }
94 + .hidden {
95 + visibility: hidden;
96 + }
97 </style>
\ No newline at end of file
src/config/themes/dark-theme.json
+6 -1
@@ -33,6 +33,7 @@
33 "foreground": "#ffffff"
34 },
35 "editor": {
36 + "background": "#171717",
37 "tabContainerBackground": "#2D2D2D",
38 "tabBackground": "#1c1c1c",
39 "tabForeground": "#ffffff",
@@ -41,7 +42,11 @@
42 "tabActiveBackground": "#171717",
43 "tabActiveForeground": "#ffffff",
44 "tabHoverBackground": "2b2b2b",
44 - "tabHoverForeground": "#ffffff"
45 + "tabHoverForeground": "#ffffff",
46 + "gutterForeground": "#898989",
47 + "gutterActiveForeground": "#ffffff",
48 + "gutterActiveBackground": "#212121",
49 + "activeLineBackground": "#212121"
50 },
51 "filetree": {
52 "treeNodeBackground": "",
src/lib/Editor.svelte new
+88
@@ -0,0 +1,88 @@
1 +<script lang="ts">
2 + import {keymap, highlightSpecialChars, drawSelection, highlightActiveLine, dropCursor,
3 + rectangularSelection, crosshairCursor,
4 + lineNumbers, highlightActiveLineGutter, EditorView} from "@codemirror/view"
5 + import {EditorState } from "@codemirror/state"
6 + import {defaultHighlightStyle, syntaxHighlighting} from "@codemirror/language"
7 + import {defaultKeymap, history, historyKeymap, indentWithTab} from "@codemirror/commands"
8 + import {searchKeymap} from "@codemirror/search"
9 + import { onMount, tick } from "svelte";
10 +
11 + let ref;
12 + let editorView;
13 + export let hidden = false;
14 + export let content = "";
15 +
16 + onMount(() => {
17 + editorView = new EditorView({
18 + parent: ref,
19 + state: EditorState.create({
20 + extensions: [
21 + lineNumbers(),
22 + highlightActiveLineGutter(),
23 + highlightSpecialChars(),
24 + highlightActiveLine(),
25 + dropCursor(),
26 + history(),
27 + drawSelection(),
28 + crosshairCursor(),
29 + rectangularSelection(),
30 + keymap.of([indentWithTab]),
31 + EditorState.allowMultipleSelections.of(true),
32 + syntaxHighlighting(defaultHighlightStyle, {fallback: true}),
33 + keymap.of([
34 + ...defaultKeymap,
35 + ...historyKeymap,
36 + ...searchKeymap,
37 + ])
38 + ],
39 + doc: content
40 + })
41 + })
42 + });
43 +</script>
44 +
45 +<div bind:this={ref} class="editor" class:hidden></div>
46 +
47 +<style lang="scss">
48 + .editor {
49 + height: 100%;
50 + width: 100%;
51 + }
52 + .hidden {
53 + display: none;
54 + }
55 + :global(.cm-editor:focus),
56 + :global(.cm-focused) {
57 + outline: none !important;
58 + }
59 + :global(.cm-editor),
60 + :global(.cm-wrap) {
61 + cursor: text;
62 + height: 100%;
63 + }
64 + :global(.cm-scroller) {
65 + font-size: 14px !important;
66 + line-height: 1.3;
67 + overflow-y: overlay;
68 + overflow-x: overlay !important;
69 + padding-top: 3px;
70 + &::-webkit-scrollbar {
71 + width: 5px;
72 + height: 5px;
73 + }
74 + &::-webkit-scrollbar-thumb {
75 + border-radius: 20px;
76 + }
77 + &::-webkit-scrollbar-corner {
78 + background-color: transparent;
79 + }
80 + }
81 + :global(.cm-content) {
82 + padding: 0 !important;
83 + }
84 + :global(.cm-lineNumbers), :global(.cm-gutterElement) {
85 + min-width: 50px !important;
86 + text-align: center !important;
87 + }
88 +</style>
\ No newline at end of file
src/lib/EditorTabList.svelte
+4 -1
@@ -34,11 +34,14 @@
34 export function addTab(path?: string, label?: string) {
35 editorTab.addTab(path, label);
36 }
37 + export function addEditorTab(path?: string, label?: string) {
38 + editorTab.addEditorTab(path, label);
39 + }
40 export function closeTab(tabid: number) {
41 editorTab.closeTab(tabid);
42 }
43
41 - let hidden = editorTab.hidden;
44 + export let hidden = editorTab.hidden;
45 let tabs = editorTab.tabs;
46 </script>
47 <div id="editor-tabs" class:hidden={$hidden}>
src/lib/Header.svelte
+2 -2
@@ -2,11 +2,11 @@
2 import { appWindow } from "@tauri-apps/api/window";
3 import Dropdown from "./utility/Dropdown.svelte";
4 import Settings from "carbon-icons-svelte/lib/Settings.svelte";
5 - import { addTab } from "../lib/EditorTabList.svelte";
5 + import { addTab, addEditorTab } from "../lib/EditorTabList.svelte";
6
7 const items = [
8 {menuname: "File", children: [
9 - {name: "New File", shortcut: "Ctrl + N", action: () => {addTab()}},
9 + {name: "New File", shortcut: "Ctrl + N", action: () => {addEditorTab()}},
10 {name: "Open File...", shortcut: "Ctrl + O", action: () => {console.log("click")}},
11 {name: "Save File", shortcut: "Ctrl + S", action: () => {console.log("click")}},
12 {name: "Save File As...", shortcut: "Ctrl + Shift + S", action: () => {console.log("click")}},
src/lib/Tab/Tab.ts
+23 -2
@@ -1,4 +1,5 @@
1 import { writable } from "svelte/store";
2 +import Editor from "../Editor.svelte";
3
4 export class Tab {
5 id = 0;
@@ -22,6 +23,7 @@ export class Tab {
23 }
24 }
25 this.tabs.set(this.tablist);
26 + this.updateView();
27 }
28 updateTabs() {
29 if (this.tablist.length === 0) {
@@ -58,6 +60,20 @@ export class Tab {
60
61 this.updateTabs();
62 }
63 + addEditorTab(path: string, label: string = "") {
64 + if (this.tabOpen(path)) {
65 + return;
66 + }
67 + let content = new Editor({target: document.getElementById("tabview"), props: {content: ""}});
68 +
69 + let tab = new this.Tab(this.id, label, content, path);
70 + tab.isfile = true;
71 + this.tablist = [...this.tablist, tab];
72 +
73 + this.updateView();
74 +
75 + this.updateTabs();
76 + }
77 closeTab(tabid: number) {
78 if (this.activeid === tabid) {
79 for (let i = 0; i <= this.tablist.length - 1; i++) {
@@ -74,7 +90,7 @@ export class Tab {
90 }
91 }
92
77 - //tablist.find(t => t.id === tabid).content.$destroy();
93 + this.tablist.find(t => t.id === tabid).content.$destroy();
94 this.tablist = this.tablist.filter(t => t.id !== tabid);
95 this.tabs.set(this.tablist);
96
@@ -83,9 +99,14 @@ export class Tab {
99 this.id = 0;
100 }
101 }
86 - CloseAllTabs() {
102 + closeAllTabs() {
103 for (const tab of this.tablist) {
104 this.closeTab(tab.id);
105 }
106 }
107 + updateView() {
108 + for (let tab of this.tablist) {
109 + tab.updateView(this.activeid);
110 + }
111 + }
112 }
src/theme.scss
+34
@@ -36,6 +36,13 @@ $tab-container-height: 2rem;
36 --editor-tabHoverBackground: #2b2b2b;
37 --editor-tabHoverForeground: #ffffff;
38
39 + --editor-background: #171717;
40 + --editor-gutter-foreground: #898989;
41 + --editor-gutter-activeForeground: #ffffff;
42 + --editor-gutter-activeBackground: #212121;
43 + --editor-activeLineBackground: #212121;
44 +
45 +
46 --filetree-treeNodeBackground: transparent;
47 --filetree-treeNodeForeground: #808080;
48 --filetree-treeNodeHoverBackground: #353535;
@@ -147,6 +154,33 @@ html {
154 }
155 }
156
157 +#tabview {
158 + margin-top: calc($tab-container-height + 5px);
159 + height: calc(100% - 6.1rem + 0.1rem);
160 +}
161 +
162 +.cm-activeLine {
163 + background-color: var(--editor-activeLineBackground) !important;
164 +}
165 +.cm-gutters {
166 + background-color: var(--editor-background) !important;
167 + color: var(--editor-gutter-foreground);
168 + border: none !important;
169 +}
170 +.cm-activeLineGutter {
171 + color: var(--editor-gutter-activeForeground) !important;
172 + background-color: var(--editor-gutter-activeBackground) !important;
173 +}
174 +.cm-scroller {
175 + background-color: var(--editor-background);
176 +}
177 +.cm-cursor {
178 + border-left-color: var(--window-foreground) !important;
179 +}
180 +.ͼ4 .cm-line::selection {
181 + background-color: #4d5054 !important;
182 +}
183 +
184 #statusbar {
185 box-shadow: 0px -1px 0 0px var(--window-borderColor);
186 height: calc($statusbar-height + 0.1rem);
yarn.lock
+111
@@ -2,6 +2,70 @@
2 # yarn lockfile v1
3
4
5 +"@codemirror/autocomplete@^6.0.0":
6 + version "6.7.1"
7 + resolved "https://registry.yarnpkg.com/@codemirror/autocomplete/-/autocomplete-6.7.1.tgz#3364799b78dff70fb8f81615536c52ea53ce40b2"
8 + integrity sha512-hSxf9S0uB+GV+gBsjY1FZNo53e1FFdzPceRfCfD1gWOnV6o21GfB5J5Wg9G/4h76XZMPrF0A6OCK/Rz5+V1egg==
9 + dependencies:
10 + "@codemirror/language" "^6.0.0"
11 + "@codemirror/state" "^6.0.0"
12 + "@codemirror/view" "^6.6.0"
13 + "@lezer/common" "^1.0.0"
14 +
15 +"@codemirror/commands@^6.0.0":
16 + version "6.2.4"
17 + resolved "https://registry.yarnpkg.com/@codemirror/commands/-/commands-6.2.4.tgz#b8a0e5ce72448c092ba4c4b1d902e6f183948aec"
18 + integrity sha512-42lmDqVH0ttfilLShReLXsDfASKLXzfyC36bzwcqzox9PlHulMcsUOfHXNo2X2aFMVNUoQ7j+d4q5bnfseYoOA==
19 + dependencies:
20 + "@codemirror/language" "^6.0.0"
21 + "@codemirror/state" "^6.2.0"
22 + "@codemirror/view" "^6.0.0"
23 + "@lezer/common" "^1.0.0"
24 +
25 +"@codemirror/language@^6.0.0":
26 + version "6.6.0"
27 + resolved "https://registry.yarnpkg.com/@codemirror/language/-/language-6.6.0.tgz#2204407174a38a68053715c19e28ad61f491779f"
28 + integrity sha512-cwUd6lzt3MfNYOobdjf14ZkLbJcnv4WtndYaoBkbor/vF+rCNguMPK0IRtvZJG4dsWiaWPcK8x1VijhvSxnstg==
29 + dependencies:
30 + "@codemirror/state" "^6.0.0"
31 + "@codemirror/view" "^6.0.0"
32 + "@lezer/common" "^1.0.0"
33 + "@lezer/highlight" "^1.0.0"
34 + "@lezer/lr" "^1.0.0"
35 + style-mod "^4.0.0"
36 +
37 +"@codemirror/lint@^6.0.0":
38 + version "6.2.1"
39 + resolved "https://registry.yarnpkg.com/@codemirror/lint/-/lint-6.2.1.tgz#654581d8cc293c315ecfa5c9d61d78c52bbd9ccd"
40 + integrity sha512-y1muai5U/uUPAGRyHMx9mHuHLypPcHWxzlZGknp/U5Mdb5Ol8Q5ZLp67UqyTbNFJJ3unVxZ8iX3g1fMN79S1JQ==
41 + dependencies:
42 + "@codemirror/state" "^6.0.0"
43 + "@codemirror/view" "^6.0.0"
44 + crelt "^1.0.5"
45 +
46 +"@codemirror/search@^6.0.0":
47 + version "6.4.0"
48 + resolved "https://registry.yarnpkg.com/@codemirror/search/-/search-6.4.0.tgz#2b256a9e0eaa9317fb48e3cc81eb2735360a59b4"
49 + integrity sha512-zMDgaBXah+nMLK2dHz9GdCnGbQu+oaGRXS1qviqNZkvOCv/whp5XZFyoikLp/23PM9RBcbuKUUISUmQHM1eRHw==
50 + dependencies:
51 + "@codemirror/state" "^6.0.0"
52 + "@codemirror/view" "^6.0.0"
53 + crelt "^1.0.5"
54 +
55 +"@codemirror/state@^6.0.0", "@codemirror/state@^6.1.4", "@codemirror/state@^6.2.0":
56 + version "6.2.0"
57 + resolved "https://registry.yarnpkg.com/@codemirror/state/-/state-6.2.0.tgz#a0fb08403ced8c2a68d1d0acee926bd20be922f2"
58 + integrity sha512-69QXtcrsc3RYtOtd+GsvczJ319udtBf1PTrr2KbLWM/e2CXUPnh0Nz9AUo8WfhSQ7GeL8dPVNUmhQVgpmuaNGA==
59 +
60 +"@codemirror/view@^6.0.0", "@codemirror/view@^6.6.0":
61 + version "6.11.2"
62 + resolved "https://registry.yarnpkg.com/@codemirror/view/-/view-6.11.2.tgz#964a746119e6d07c75fddecaf90cb463ccf59f71"
63 + integrity sha512-AzxJ9Aub6ubBvoPBGvjcd4zITqcBBiLpJ89z0ZjnphOHncbvUvQcb9/WMVGpuwTT95+jW4knkH6gFIy0oLdaUQ==
64 + dependencies:
65 + "@codemirror/state" "^6.1.4"
66 + style-mod "^4.0.0"
67 + w3c-keyname "^2.2.4"
68 +
69 "@esbuild/android-arm64@0.17.17":
70 version "0.17.17"
71 resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.17.tgz#164b054d58551f8856285f386e1a8f45d9ba3a31"
@@ -135,6 +199,25 @@
199 "@jridgewell/resolve-uri" "3.1.0"
200 "@jridgewell/sourcemap-codec" "1.4.14"
201
202 +"@lezer/common@^1.0.0":
203 + version "1.0.2"
204 + resolved "https://registry.yarnpkg.com/@lezer/common/-/common-1.0.2.tgz#8fb9b86bdaa2ece57e7d59e5ffbcb37d71815087"
205 + integrity sha512-SVgiGtMnMnW3ActR8SXgsDhw7a0w0ChHSYAyAUxxrOiJ1OqYWEKk/xJd84tTSPo1mo6DXLObAJALNnd0Hrv7Ng==
206 +
207 +"@lezer/highlight@^1.0.0":
208 + version "1.1.4"
209 + resolved "https://registry.yarnpkg.com/@lezer/highlight/-/highlight-1.1.4.tgz#98ed821e89f72981b7ba590474e6ee86c8185619"
210 + integrity sha512-IECkFmw2l7sFcYXrV8iT9GeY4W0fU4CxX0WMwhmhMIVjoDdD1Hr6q3G2NqVtLg/yVe5n7i4menG3tJ2r4eCrPQ==
211 + dependencies:
212 + "@lezer/common" "^1.0.0"
213 +
214 +"@lezer/lr@^1.0.0":
215 + version "1.3.4"
216 + resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-1.3.4.tgz#8795bf2ba4f69b998e8fb4b5a7c57ea68753474c"
217 + integrity sha512-7o+e4og/QoC/6btozDPJqnzBhUaD1fMfmvnEKQO1wRRiTse1WxaJ3OMEXZJnkgT6HCcTVOctSoXK9jGJw2oe9g==
218 + dependencies:
219 + "@lezer/common" "^1.0.0"
220 +
221 "@nodelib/fs.scandir@2.1.5":
222 version "2.1.5"
223 resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
@@ -311,11 +394,29 @@ carbon-icons-svelte@^11.4.0:
394 optionalDependencies:
395 fsevents "~2.3.2"
396
397 +codemirror@^6.0.1:
398 + version "6.0.1"
399 + resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-6.0.1.tgz#62b91142d45904547ee3e0e0e4c1a79158035a29"
400 + integrity sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==
401 + dependencies:
402 + "@codemirror/autocomplete" "^6.0.0"
403 + "@codemirror/commands" "^6.0.0"
404 + "@codemirror/language" "^6.0.0"
405 + "@codemirror/lint" "^6.0.0"
406 + "@codemirror/search" "^6.0.0"
407 + "@codemirror/state" "^6.0.0"
408 + "@codemirror/view" "^6.0.0"
409 +
410 concat-map@0.0.1:
411 version "0.0.1"
412 resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
413 integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
414
415 +crelt@^1.0.5:
416 + version "1.0.5"
417 + resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.5.tgz#57c0d52af8c859e354bace1883eb2e1eb182bb94"
418 + integrity sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==
419 +
420 debug@^4.3.4:
421 version "4.3.4"
422 resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
@@ -735,6 +836,11 @@ strip-indent@^3.0.0:
836 dependencies:
837 min-indent "^1.0.0"
838
839 +style-mod@^4.0.0:
840 + version "4.0.3"
841 + resolved "https://registry.yarnpkg.com/style-mod/-/style-mod-4.0.3.tgz#136c4abc905f82a866a18b39df4dc08ec762b1ad"
842 + integrity sha512-78Jv8kYJdjbvRwwijtCevYADfsI0lGzYJe4mMFdceO8l75DFFDoqBhR1jVDicDRRaX4//g1u9wKeo+ztc2h1Rw==
843 +
844 supports-preserve-symlinks-flag@^1.0.0:
845 version "1.0.0"
846 resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
@@ -816,6 +922,11 @@ vitefu@^0.2.4:
922 resolved "https://registry.yarnpkg.com/vitefu/-/vitefu-0.2.4.tgz#212dc1a9d0254afe65e579351bed4e25d81e0b35"
923 integrity sha512-fanAXjSaf9xXtOOeno8wZXIhgia+CZury481LsDaV++lSvcU2R9Ch2bPh3PYFyoHW+w9LqAeYRISVQjUIew14g==
924
925 +w3c-keyname@^2.2.4:
926 + version "2.2.6"
927 + resolved "https://registry.yarnpkg.com/w3c-keyname/-/w3c-keyname-2.2.6.tgz#8412046116bc16c5d73d4e612053ea10a189c85f"
928 + integrity sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg==
929 +
930 wrappy@1:
931 version "1.0.2"
932 resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"