gitlatex 1.5.2__tar.gz → 1.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {gitlatex-1.5.2 → gitlatex-1.7.0}/PKG-INFO +6 -3
- {gitlatex-1.5.2 → gitlatex-1.7.0}/README.md +5 -2
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/__init__.py +1 -1
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/app.js +20 -0
- gitlatex-1.7.0/gitlatex/public/css/editor.css +255 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/css/settings.css +122 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/index.html +94 -1
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/build/compile.js +7 -8
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/editor/monaco.js +37 -25
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/editor/session.js +6 -6
- gitlatex-1.7.0/gitlatex/public/js/editor/snippets.js +333 -0
- gitlatex-1.7.0/gitlatex/public/js/editor/synctex.js +102 -0
- gitlatex-1.7.0/gitlatex/public/js/editor/vim.js +122 -0
- gitlatex-1.7.0/gitlatex/public/js/editor/vimtex.js +673 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/git/actions.js +14 -1
- gitlatex-1.7.0/gitlatex/public/js/ui/pdfviewer.js +334 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/ui/settings.js +5 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/routes/__init__.py +7 -1
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/routes/git.py +10 -2
- gitlatex-1.7.0/gitlatex/routes/snippets.py +22 -0
- gitlatex-1.7.0/gitlatex/routes/synctex.py +78 -0
- gitlatex-1.7.0/gitlatex/services/snippets.py +90 -0
- gitlatex-1.7.0/gitlatex/services/synctex.py +118 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex.egg-info/PKG-INFO +6 -3
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex.egg-info/SOURCES.txt +9 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/pyproject.toml +1 -1
- gitlatex-1.5.2/gitlatex/public/css/editor.css +0 -97
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/__main__.py +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/app.py +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/http.py +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/bib-commands.json +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/css/base.css +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/css/console.css +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/css/docs.css +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/css/home.css +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/css/layout.css +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/css/loading.css +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/css/outline.css +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/css/problems.css +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/css/sidebar.css +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/css/support.css +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/css/toolbar.css +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/css/updates.css +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/css/versions.css +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/favicon.svg +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/build/problems.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/core/api.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/core/filetypes.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/core/router.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/core/state.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/core/storage.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/editor/completions.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/editor/envcolors.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/editor/filetree.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/editor/languages.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/editor/mainfile.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/editor/outline.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/editor/projectindex.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/editor/spell.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/git/diffview.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/git/menu.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/git/versions.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/home/repolist.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/ui/consolepane.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/ui/layout.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/ui/loading.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/ui/modals.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/ui/theme.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/js/ui/viewer.js +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/public/latex-commands.json +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/routes/compile.py +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/routes/files.py +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/routes/pages.py +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/routes/projectindex.py +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/routes/repos.py +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/routes/spell.py +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/routes/system.py +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/server.py +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/services/__init__.py +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/services/git_backend.py +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/services/gitrepo.py +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/services/latex.py +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/services/paths.py +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/services/projectindex.py +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/services/spell.py +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/services/updates.py +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex/state.py +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex.egg-info/dependency_links.txt +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex.egg-info/entry_points.txt +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex.egg-info/requires.txt +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/gitlatex.egg-info/top_level.txt +0 -0
- {gitlatex-1.5.2 → gitlatex-1.7.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gitlatex
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.7.0
|
|
4
4
|
Summary: A simple UI for LaTeX projects with Git support. Clone repos, edit, compile, and push.
|
|
5
5
|
License-Expression: ISC
|
|
6
6
|
Project-URL: Homepage, https://github.com/abdussamiakanda/gitlatex
|
|
@@ -152,8 +152,11 @@ powers VS Code.
|
|
|
152
152
|
|
|
153
153
|
### Git and version history
|
|
154
154
|
|
|
155
|
-
- **Status, diff, pull and push** from the toolbar. Push
|
|
156
|
-
|
|
155
|
+
- **Status, diff, pull and push** from the toolbar. Push asks for a commit message
|
|
156
|
+
(default: `Update LaTeX project`), then stages everything, commits and pushes.
|
|
157
|
+
Edit the message or accept the default; Cancel or Escape stops the
|
|
158
|
+
operation. Submitting an empty message also cancels. If the working tree is
|
|
159
|
+
clean, existing commits are pushed without creating an empty commit.
|
|
157
160
|
- Pull and push **enable themselves only when there is something to do**, with
|
|
158
161
|
ahead/behind counts read from the remote.
|
|
159
162
|
- **Version history panel** listing your commits, with the files each one touched
|
|
@@ -124,8 +124,11 @@ powers VS Code.
|
|
|
124
124
|
|
|
125
125
|
### Git and version history
|
|
126
126
|
|
|
127
|
-
- **Status, diff, pull and push** from the toolbar. Push
|
|
128
|
-
|
|
127
|
+
- **Status, diff, pull and push** from the toolbar. Push asks for a commit message
|
|
128
|
+
(default: `Update LaTeX project`), then stages everything, commits and pushes.
|
|
129
|
+
Edit the message or accept the default; Cancel or Escape stops the
|
|
130
|
+
operation. Submitting an empty message also cancels. If the working tree is
|
|
131
|
+
clean, existing commits are pushed without creating an empty commit.
|
|
129
132
|
- Pull and push **enable themselves only when there is something to do**, with
|
|
130
133
|
ahead/behind counts read from the remote.
|
|
131
134
|
- **Version history panel** listing your commits, with the files each one touched
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""GitLaTeX IDE - LaTeX projects with Git support."""
|
|
2
|
-
__version__ = "1.
|
|
2
|
+
__version__ = "1.7.0"
|
|
@@ -15,7 +15,9 @@ import { setCompilerApi, setCompilerApiKey, setLatexEngine, setUseCompilerApi }
|
|
|
15
15
|
import { addNewFileSidebar, addNewFolderSidebar, handleSidebarFileInputChange, uploadFilesSidebar } from "./js/editor/filetree.js";
|
|
16
16
|
import { populateMainFileDropdown } from "./js/editor/mainfile.js";
|
|
17
17
|
import { toggleOutlineSection } from "./js/editor/outline.js";
|
|
18
|
+
import { closeSnippetForm, exportSnippets, importSnippetsFile, openSnippetForm, submitSnippetForm } from "./js/editor/snippets.js";
|
|
18
19
|
import { setSpellCheckEnabled } from "./js/editor/spell.js";
|
|
20
|
+
import { setVimEnabled } from "./js/editor/vim.js";
|
|
19
21
|
import { hideDiffView } from "./js/git/diffview.js";
|
|
20
22
|
import { closeGitDropdown, toggleGitDropdown } from "./js/git/menu.js";
|
|
21
23
|
import { pullChanges, pushChanges, showDiff, showStatus } from "./js/git/actions.js";
|
|
@@ -23,6 +25,8 @@ import { clearCompareSelection, closeVersionsPanel, loadCommits, loadComparison,
|
|
|
23
25
|
import { cloneRepoAndRefresh, closeCloneModal, closeCreateWorkspaceModal, createWorkspaceAndOpen, initRepoListControls, openCloneModal, openCreateWorkspaceModal } from "./js/home/repolist.js";
|
|
24
26
|
import { showConsoleTab } from "./js/ui/consolepane.js";
|
|
25
27
|
import { setupResizers, toggleSidebar } from "./js/ui/layout.js";
|
|
28
|
+
import { initPdfViewer, setPdfDoubleClickHandler } from "./js/ui/pdfviewer.js";
|
|
29
|
+
import { syncFromPdf } from "./js/editor/synctex.js";
|
|
26
30
|
import { checkForUpdate, syncCompilerApiFields } from "./js/ui/settings.js";
|
|
27
31
|
import { getStoredTheme, setTheme } from "./js/ui/theme.js";
|
|
28
32
|
|
|
@@ -55,6 +59,8 @@ document.addEventListener("click", function (e) {
|
|
|
55
59
|
document.documentElement.setAttribute("data-theme", getStoredTheme());
|
|
56
60
|
populateMainFileDropdown();
|
|
57
61
|
initRepoListControls();
|
|
62
|
+
initPdfViewer();
|
|
63
|
+
setPdfDoubleClickHandler(syncFromPdf);
|
|
58
64
|
document.getElementById("versions-close")?.addEventListener("click", closeVersionsPanel);
|
|
59
65
|
document.getElementById("versions-refresh")?.addEventListener("click", loadCommits);
|
|
60
66
|
document.getElementById("diff-view-close")?.addEventListener("click", hideDiffView);
|
|
@@ -74,6 +80,20 @@ document.getElementById("settings-use-api")?.addEventListener("change", function
|
|
|
74
80
|
document.getElementById("settings-spellcheck")?.addEventListener("change", function () {
|
|
75
81
|
setSpellCheckEnabled(this.checked);
|
|
76
82
|
});
|
|
83
|
+
document.getElementById("settings-vim")?.addEventListener("change", function () {
|
|
84
|
+
setVimEnabled(this.checked);
|
|
85
|
+
});
|
|
86
|
+
document.getElementById("snippets-new")?.addEventListener("click", () => openSnippetForm(-1));
|
|
87
|
+
document.getElementById("snippet-cancel")?.addEventListener("click", closeSnippetForm);
|
|
88
|
+
document.getElementById("snippet-save")?.addEventListener("click", submitSnippetForm);
|
|
89
|
+
document.getElementById("snippets-export")?.addEventListener("click", exportSnippets);
|
|
90
|
+
document.getElementById("snippets-import")?.addEventListener("click", function () {
|
|
91
|
+
document.getElementById("snippets-import-input")?.click();
|
|
92
|
+
});
|
|
93
|
+
document.getElementById("snippets-import-input")?.addEventListener("change", function () {
|
|
94
|
+
if (this.files && this.files[0]) importSnippetsFile(this.files[0]);
|
|
95
|
+
this.value = "";
|
|
96
|
+
});
|
|
77
97
|
document.getElementById("compare-swap")?.addEventListener("click", function () {
|
|
78
98
|
state.compareOrderSwapped = !state.compareOrderSwapped;
|
|
79
99
|
renderCompareBar();
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The editor pane and the PDF preview beside it.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/* --- Editor pane (contains editor and file viewer) --- */
|
|
6
|
+
#editor-pane {
|
|
7
|
+
flex: 1 1 0;
|
|
8
|
+
min-width: 180px;
|
|
9
|
+
min-height: 0;
|
|
10
|
+
width: 0;
|
|
11
|
+
border-right: 1px solid var(--border-subtle);
|
|
12
|
+
position: relative;
|
|
13
|
+
overflow: hidden;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
#editor {
|
|
17
|
+
position: absolute;
|
|
18
|
+
inset: 0;
|
|
19
|
+
min-height: 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
#editor-pane.viewer-active #editor {
|
|
23
|
+
visibility: hidden;
|
|
24
|
+
pointer-events: none;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
#file-viewer {
|
|
28
|
+
position: absolute;
|
|
29
|
+
inset: 0;
|
|
30
|
+
display: flex;
|
|
31
|
+
align-items: center;
|
|
32
|
+
justify-content: center;
|
|
33
|
+
background: var(--bg-app);
|
|
34
|
+
overflow: auto;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
#file-viewer.hidden {
|
|
38
|
+
display: none !important;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.file-viewer-content {
|
|
42
|
+
max-width: 100%;
|
|
43
|
+
max-height: 100%;
|
|
44
|
+
object-fit: contain;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
#file-viewer-pdf.file-viewer-content {
|
|
48
|
+
width: 100%;
|
|
49
|
+
height: 100%;
|
|
50
|
+
border: none;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
#file-viewer-pdf.hidden {
|
|
54
|
+
display: none !important;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.file-viewer-unavailable {
|
|
58
|
+
color: var(--text-muted, #888);
|
|
59
|
+
font-size: 1rem;
|
|
60
|
+
padding: 1rem;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.file-viewer-unavailable.hidden {
|
|
64
|
+
display: none !important;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* Monaco fills the pane; absolute so it stays within #editor below the navbar */
|
|
68
|
+
#editor > .monaco-editor {
|
|
69
|
+
position: absolute !important;
|
|
70
|
+
top: 0 !important;
|
|
71
|
+
right: 0 !important;
|
|
72
|
+
bottom: 0 !important;
|
|
73
|
+
left: 0 !important;
|
|
74
|
+
width: 100% !important;
|
|
75
|
+
height: 100% !important;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* --- PDF pane (drawn by js/ui/pdfviewer.js) --- */
|
|
79
|
+
#pdf {
|
|
80
|
+
width: var(--pdf-width);
|
|
81
|
+
min-width: 200px;
|
|
82
|
+
flex: 0 0 auto;
|
|
83
|
+
height: 100%;
|
|
84
|
+
display: flex;
|
|
85
|
+
flex-direction: column;
|
|
86
|
+
position: relative;
|
|
87
|
+
background: var(--bg-app);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.pdf-toolbar {
|
|
91
|
+
display: flex;
|
|
92
|
+
align-items: center;
|
|
93
|
+
gap: 2px;
|
|
94
|
+
padding: 2px 8px;
|
|
95
|
+
border-bottom: 1px solid var(--border-subtle);
|
|
96
|
+
background: var(--bg-elevated);
|
|
97
|
+
flex: 0 0 auto;
|
|
98
|
+
min-width: 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.pdf-toolbar .icon-btn {
|
|
102
|
+
width: 28px;
|
|
103
|
+
height: 28px;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.pdf-zoom-label {
|
|
107
|
+
min-width: 3.2em;
|
|
108
|
+
text-align: center;
|
|
109
|
+
font-size: 0.8rem;
|
|
110
|
+
color: var(--text-secondary);
|
|
111
|
+
font-variant-numeric: tabular-nums;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.pdf-toolbar-hint {
|
|
115
|
+
margin-left: auto;
|
|
116
|
+
font-size: 0.75rem;
|
|
117
|
+
color: var(--text-muted);
|
|
118
|
+
white-space: nowrap;
|
|
119
|
+
overflow: hidden;
|
|
120
|
+
text-overflow: ellipsis;
|
|
121
|
+
min-width: 0;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
#pdf-pages {
|
|
125
|
+
flex: 1 1 0;
|
|
126
|
+
min-height: 0;
|
|
127
|
+
overflow: auto;
|
|
128
|
+
position: relative;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
#pdf-pages.hidden,
|
|
132
|
+
#pdf-fallback.hidden,
|
|
133
|
+
.pdf-empty.hidden {
|
|
134
|
+
display: none;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/* Padding here is PAGE_PADDING in pdfviewer.js. max-content + margin auto
|
|
138
|
+
centres pages that fit and lets zoomed ones scroll sideways. */
|
|
139
|
+
.pdf-pages-inner {
|
|
140
|
+
padding: 12px;
|
|
141
|
+
width: max-content;
|
|
142
|
+
min-width: 100%;
|
|
143
|
+
box-sizing: border-box;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.pdf-pages-inner.staging {
|
|
147
|
+
position: absolute;
|
|
148
|
+
top: 0;
|
|
149
|
+
left: 0;
|
|
150
|
+
visibility: hidden;
|
|
151
|
+
pointer-events: none;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.pdf-page {
|
|
155
|
+
position: relative;
|
|
156
|
+
margin: 0 auto 12px;
|
|
157
|
+
background: #fff;
|
|
158
|
+
box-shadow: var(--shadow-md);
|
|
159
|
+
user-select: none;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.pdf-page canvas {
|
|
163
|
+
display: block;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.pdf-sync-mark {
|
|
167
|
+
position: absolute;
|
|
168
|
+
background: rgba(241, 80, 47, 0.28);
|
|
169
|
+
outline: 1px solid rgba(241, 80, 47, 0.7);
|
|
170
|
+
border-radius: 2px;
|
|
171
|
+
pointer-events: none;
|
|
172
|
+
animation: pdf-sync-fade 1.8s ease-out forwards;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@keyframes pdf-sync-fade {
|
|
176
|
+
0%, 60% { opacity: 1; }
|
|
177
|
+
100% { opacity: 0; }
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
#pdf-fallback {
|
|
181
|
+
flex: 1 1 0;
|
|
182
|
+
min-height: 0;
|
|
183
|
+
width: 100%;
|
|
184
|
+
border: none;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.pdf-empty {
|
|
188
|
+
position: absolute;
|
|
189
|
+
inset: 34px 0 0 0;
|
|
190
|
+
display: flex;
|
|
191
|
+
align-items: center;
|
|
192
|
+
justify-content: center;
|
|
193
|
+
color: var(--text-muted);
|
|
194
|
+
font-size: 0.9rem;
|
|
195
|
+
pointer-events: none;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* Editor line flashed after a jump from the PDF */
|
|
199
|
+
.monaco-editor .synctex-line-flash {
|
|
200
|
+
background: rgba(241, 80, 47, 0.22);
|
|
201
|
+
animation: pdf-sync-fade 1.5s ease-out forwards;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/* Sidebar hidden: collapse with animation */
|
|
205
|
+
.sidebar-hidden #sidebar {
|
|
206
|
+
width: 0;
|
|
207
|
+
min-width: 0;
|
|
208
|
+
border-right-color: transparent;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.sidebar-hidden #editor-pane {
|
|
212
|
+
flex: 1;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/* --- Vim mode status bar (js/editor/vim.js) --- */
|
|
216
|
+
.vim-statusbar {
|
|
217
|
+
display: none;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
#editor-pane.vim-on #editor {
|
|
221
|
+
bottom: 24px;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
#editor-pane.vim-on .vim-statusbar {
|
|
225
|
+
position: absolute;
|
|
226
|
+
left: 0;
|
|
227
|
+
right: 0;
|
|
228
|
+
bottom: 0;
|
|
229
|
+
height: 24px;
|
|
230
|
+
display: flex;
|
|
231
|
+
align-items: center;
|
|
232
|
+
gap: 12px;
|
|
233
|
+
padding: 0 10px;
|
|
234
|
+
font-family: var(--font-mono);
|
|
235
|
+
font-size: 12px;
|
|
236
|
+
color: var(--text-secondary);
|
|
237
|
+
background: var(--bg-elevated);
|
|
238
|
+
border-top: 1px solid var(--border-subtle);
|
|
239
|
+
box-sizing: border-box;
|
|
240
|
+
overflow: hidden;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
#editor-pane.viewer-active .vim-statusbar {
|
|
244
|
+
visibility: hidden;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.vim-statusbar input {
|
|
248
|
+
flex: 1 1 auto;
|
|
249
|
+
min-width: 0;
|
|
250
|
+
font: inherit;
|
|
251
|
+
color: var(--text-primary);
|
|
252
|
+
background: transparent;
|
|
253
|
+
border: none;
|
|
254
|
+
outline: none;
|
|
255
|
+
}
|
|
@@ -393,3 +393,125 @@
|
|
|
393
393
|
#settings-test-api.hidden {
|
|
394
394
|
display: none;
|
|
395
395
|
}
|
|
396
|
+
|
|
397
|
+
/* --- Settings: Vim help and snippets --- */
|
|
398
|
+
.vimtex-help summary {
|
|
399
|
+
font-size: 12px;
|
|
400
|
+
color: var(--accent);
|
|
401
|
+
cursor: pointer;
|
|
402
|
+
margin-top: 2px;
|
|
403
|
+
}
|
|
404
|
+
.vimtex-table {
|
|
405
|
+
width: 100%;
|
|
406
|
+
margin-top: 8px;
|
|
407
|
+
border-collapse: collapse;
|
|
408
|
+
font-size: 12px;
|
|
409
|
+
color: var(--text-secondary);
|
|
410
|
+
}
|
|
411
|
+
.vimtex-table th,
|
|
412
|
+
.vimtex-table td {
|
|
413
|
+
padding: 4px 0;
|
|
414
|
+
text-align: left;
|
|
415
|
+
vertical-align: top;
|
|
416
|
+
border-top: 1px solid var(--border-subtle);
|
|
417
|
+
}
|
|
418
|
+
.vimtex-table th {
|
|
419
|
+
font-weight: 400;
|
|
420
|
+
white-space: nowrap;
|
|
421
|
+
padding-right: 12px;
|
|
422
|
+
width: 1%;
|
|
423
|
+
}
|
|
424
|
+
.vimtex-table code,
|
|
425
|
+
.snippet-prefix {
|
|
426
|
+
font-family: var(--font-mono);
|
|
427
|
+
font-size: 11px;
|
|
428
|
+
padding: 1px 4px;
|
|
429
|
+
background: var(--bg-hover);
|
|
430
|
+
border-radius: 3px;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.snippets-list {
|
|
434
|
+
display: flex;
|
|
435
|
+
flex-direction: column;
|
|
436
|
+
}
|
|
437
|
+
.snippet-row {
|
|
438
|
+
display: flex;
|
|
439
|
+
align-items: center;
|
|
440
|
+
gap: 10px;
|
|
441
|
+
padding: 4px 0;
|
|
442
|
+
border-top: 1px solid var(--border-subtle);
|
|
443
|
+
font-size: 12px;
|
|
444
|
+
}
|
|
445
|
+
.snippet-row:first-child {
|
|
446
|
+
border-top: none;
|
|
447
|
+
}
|
|
448
|
+
.snippet-prefix {
|
|
449
|
+
flex-shrink: 0;
|
|
450
|
+
color: var(--text-primary);
|
|
451
|
+
}
|
|
452
|
+
.snippet-desc {
|
|
453
|
+
flex: 1 1 auto;
|
|
454
|
+
min-width: 0;
|
|
455
|
+
color: var(--text-secondary);
|
|
456
|
+
white-space: nowrap;
|
|
457
|
+
overflow: hidden;
|
|
458
|
+
text-overflow: ellipsis;
|
|
459
|
+
}
|
|
460
|
+
.snippet-scope {
|
|
461
|
+
flex-shrink: 0;
|
|
462
|
+
color: var(--text-muted);
|
|
463
|
+
font-size: 11px;
|
|
464
|
+
}
|
|
465
|
+
.snippet-row .snippet-action {
|
|
466
|
+
width: 26px;
|
|
467
|
+
height: 26px;
|
|
468
|
+
flex-shrink: 0;
|
|
469
|
+
}
|
|
470
|
+
.snippet-row .snippet-action .material-icons {
|
|
471
|
+
font-size: 16px;
|
|
472
|
+
}
|
|
473
|
+
.snippets-empty.hidden,
|
|
474
|
+
.snippet-form.hidden {
|
|
475
|
+
display: none;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.snippet-form {
|
|
479
|
+
display: flex;
|
|
480
|
+
flex-direction: column;
|
|
481
|
+
gap: 4px;
|
|
482
|
+
margin-top: 8px;
|
|
483
|
+
padding: 12px;
|
|
484
|
+
border: 1px solid var(--border-subtle);
|
|
485
|
+
border-radius: var(--radius-sm);
|
|
486
|
+
}
|
|
487
|
+
.snippet-form .settings-label {
|
|
488
|
+
margin-top: 6px;
|
|
489
|
+
}
|
|
490
|
+
.snippet-form-row {
|
|
491
|
+
display: flex;
|
|
492
|
+
gap: 12px;
|
|
493
|
+
}
|
|
494
|
+
.snippet-field {
|
|
495
|
+
flex: 1 1 auto;
|
|
496
|
+
display: flex;
|
|
497
|
+
flex-direction: column;
|
|
498
|
+
gap: 4px;
|
|
499
|
+
min-width: 0;
|
|
500
|
+
}
|
|
501
|
+
.snippet-field .settings-label {
|
|
502
|
+
margin-top: 0;
|
|
503
|
+
}
|
|
504
|
+
.snippet-field-scope {
|
|
505
|
+
flex: 0 0 100px;
|
|
506
|
+
}
|
|
507
|
+
.snippet-body {
|
|
508
|
+
font-family: var(--font-mono);
|
|
509
|
+
font-size: 12px;
|
|
510
|
+
line-height: 1.5;
|
|
511
|
+
resize: vertical;
|
|
512
|
+
white-space: pre;
|
|
513
|
+
tab-size: 2;
|
|
514
|
+
}
|
|
515
|
+
.settings-actions .btn-toolbar {
|
|
516
|
+
white-space: nowrap;
|
|
517
|
+
}
|
|
@@ -206,6 +206,81 @@
|
|
|
206
206
|
Underlines unknown words in .tex, .txt and .md files. Comments, math and
|
|
207
207
|
command arguments are skipped.
|
|
208
208
|
</p>
|
|
209
|
+
<label class="settings-toggle" for="settings-vim">
|
|
210
|
+
<span class="settings-toggle-text">Vim keybindings</span>
|
|
211
|
+
<input type="checkbox" id="settings-vim" class="switch-input">
|
|
212
|
+
<span class="switch" aria-hidden="true"></span>
|
|
213
|
+
</label>
|
|
214
|
+
<p class="settings-hint">
|
|
215
|
+
Normal, insert and visual modes with <code>:w</code>, plus VimTeX-style
|
|
216
|
+
mappings in .tex files.
|
|
217
|
+
</p>
|
|
218
|
+
<details class="vimtex-help">
|
|
219
|
+
<summary>VimTeX mappings</summary>
|
|
220
|
+
<table class="vimtex-table">
|
|
221
|
+
<tbody>
|
|
222
|
+
<tr><th><code>ie</code> <code>ae</code></th><td>Inner / around environment</td></tr>
|
|
223
|
+
<tr><th><code>i$</code> <code>a$</code></th><td>Inner / around math</td></tr>
|
|
224
|
+
<tr><th><code>ic</code> <code>ac</code></th><td>Inner / around command</td></tr>
|
|
225
|
+
<tr><th><code>id</code> <code>ad</code></th><td>Inner / around delimiters</td></tr>
|
|
226
|
+
<tr><th><code>iP</code> <code>aP</code></th><td>Inner / around section</td></tr>
|
|
227
|
+
<tr><th><code>]]</code> <code>[[</code></th><td>Next / previous section</td></tr>
|
|
228
|
+
<tr><th><code>]m</code> <code>[m</code> <code>]M</code> <code>[M</code></th><td>Next / previous <code>\begin</code>, <code>\end</code></td></tr>
|
|
229
|
+
<tr><th><code>]n</code> <code>[n</code></th><td>Next / previous math</td></tr>
|
|
230
|
+
<tr><th><code>%</code></th><td>Jump between <code>\begin</code> and <code>\end</code>, or brackets</td></tr>
|
|
231
|
+
<tr><th><code>dse</code> <code>cse</code> <code>tse</code></th><td>Delete / change / toggle-star environment</td></tr>
|
|
232
|
+
<tr><th><code>dsc</code> <code>csc</code> <code>tsc</code></th><td>Delete / change / toggle-star command</td></tr>
|
|
233
|
+
<tr><th><code>ds$</code> <code>cs$</code> <code>ts$</code></th><td>Delete / change math, toggle inline ↔ display</td></tr>
|
|
234
|
+
<tr><th><code>dsd</code> <code>tsd</code></th><td>Delete delimiters, toggle <code>\left</code>/<code>\right</code></td></tr>
|
|
235
|
+
<tr><th><code>tsf</code></th><td>Toggle <code>\frac{a}{b}</code> ↔ <code>a/b</code></td></tr>
|
|
236
|
+
<tr><th><code>]]</code> (insert)</th><td>Close the current environment</td></tr>
|
|
237
|
+
<tr><th><code>\ll</code> <code>\lv</code></th><td>Compile, show cursor in PDF</td></tr>
|
|
238
|
+
<tr><th><code>\lt</code> <code>\le</code></th><td>Toggle outline, show errors</td></tr>
|
|
239
|
+
</tbody>
|
|
240
|
+
</table>
|
|
241
|
+
</details>
|
|
242
|
+
</div>
|
|
243
|
+
<div class="settings-group settings-group-stack">
|
|
244
|
+
<label class="settings-label">Snippets</label>
|
|
245
|
+
<p class="settings-hint">
|
|
246
|
+
Type a snippet's prefix and press <code>Tab</code>, or pick it from the suggestions.
|
|
247
|
+
Bodies use <code>$1</code>, <code>${1:default}</code> and <code>$0</code> for tab stops.
|
|
248
|
+
Tip: select text in the editor and right-click → <em>Save Selection as Snippet</em>.
|
|
249
|
+
</p>
|
|
250
|
+
<div id="snippets-list" class="snippets-list"></div>
|
|
251
|
+
<p id="snippets-empty" class="settings-hint snippets-empty hidden">No snippets yet.</p>
|
|
252
|
+
<div id="snippet-form" class="snippet-form hidden">
|
|
253
|
+
<div class="snippet-form-row">
|
|
254
|
+
<div class="snippet-field">
|
|
255
|
+
<label class="settings-label" for="snippet-prefix">Prefix</label>
|
|
256
|
+
<input type="text" id="snippet-prefix" class="settings-input" placeholder="fig" autocomplete="off" spellcheck="false">
|
|
257
|
+
</div>
|
|
258
|
+
<div class="snippet-field snippet-field-scope">
|
|
259
|
+
<label class="settings-label" for="snippet-scope">Files</label>
|
|
260
|
+
<select id="snippet-scope" class="settings-input">
|
|
261
|
+
<option value="latex">.tex</option>
|
|
262
|
+
<option value="bib">.bib</option>
|
|
263
|
+
<option value="all">All</option>
|
|
264
|
+
</select>
|
|
265
|
+
</div>
|
|
266
|
+
</div>
|
|
267
|
+
<label class="settings-label" for="snippet-description">Description</label>
|
|
268
|
+
<input type="text" id="snippet-description" class="settings-input" placeholder="Figure with caption and label" autocomplete="off">
|
|
269
|
+
<label class="settings-label" for="snippet-body">Body</label>
|
|
270
|
+
<textarea id="snippet-body" class="settings-input snippet-body" rows="7" spellcheck="false"
|
|
271
|
+
placeholder="\begin{figure}[${1:htbp}] \centering \includegraphics[width=\linewidth]{$2} \caption{$3} \label{fig:$4} \end{figure}$0"></textarea>
|
|
272
|
+
<div class="settings-actions">
|
|
273
|
+
<button type="button" class="btn-toolbar" id="snippet-cancel">Cancel</button>
|
|
274
|
+
<button type="button" class="btn-toolbar primary" id="snippet-save">Save snippet</button>
|
|
275
|
+
</div>
|
|
276
|
+
</div>
|
|
277
|
+
<div class="settings-actions">
|
|
278
|
+
<span id="snippets-status" class="settings-save-status"></span>
|
|
279
|
+
<button type="button" class="btn-toolbar" id="snippets-import" title="Import a GitLaTeX or VS Code snippets .json file">Import</button>
|
|
280
|
+
<button type="button" class="btn-toolbar" id="snippets-export">Export</button>
|
|
281
|
+
<button type="button" class="btn-toolbar primary" id="snippets-new">New snippet</button>
|
|
282
|
+
<input type="file" id="snippets-import-input" accept=".json,.code-snippets,application/json" hidden>
|
|
283
|
+
</div>
|
|
209
284
|
</div>
|
|
210
285
|
<div class="settings-group settings-group-stack settings-tech-info">
|
|
211
286
|
<label class="settings-label">Technical info</label>
|
|
@@ -599,6 +674,7 @@ app.listen(8080, () => console.log("Compiler API on http://localhost:8080/compil
|
|
|
599
674
|
<div class="resizer resizer-v" id="resizer-sidebar" title="Resize sidebar"></div>
|
|
600
675
|
<div id="editor-pane">
|
|
601
676
|
<div id="editor"></div>
|
|
677
|
+
<div id="vim-statusbar" class="vim-statusbar" aria-live="polite"></div>
|
|
602
678
|
<div id="file-viewer" class="hidden" aria-hidden="true">
|
|
603
679
|
<img id="file-viewer-img" alt="" class="file-viewer-content">
|
|
604
680
|
<iframe id="file-viewer-pdf" class="file-viewer-content hidden" title="PDF viewer"></iframe>
|
|
@@ -620,7 +696,24 @@ app.listen(8080, () => console.log("Compiler API on http://localhost:8080/compil
|
|
|
620
696
|
</div>
|
|
621
697
|
</div>
|
|
622
698
|
<div class="resizer resizer-v" id="resizer-pdf" title="Resize editor / PDF"></div>
|
|
623
|
-
<
|
|
699
|
+
<div id="pdf">
|
|
700
|
+
<div class="pdf-toolbar">
|
|
701
|
+
<button type="button" class="icon-btn" id="pdf-zoom-out" title="Zoom out" aria-label="Zoom out">
|
|
702
|
+
<span class="material-icons" aria-hidden="true">remove</span>
|
|
703
|
+
</button>
|
|
704
|
+
<span id="pdf-zoom-label" class="pdf-zoom-label">100%</span>
|
|
705
|
+
<button type="button" class="icon-btn" id="pdf-zoom-in" title="Zoom in" aria-label="Zoom in">
|
|
706
|
+
<span class="material-icons" aria-hidden="true">add</span>
|
|
707
|
+
</button>
|
|
708
|
+
<button type="button" class="icon-btn" id="pdf-fit-width" title="Fit width" aria-label="Fit width">
|
|
709
|
+
<span class="material-icons" aria-hidden="true">fit_screen</span>
|
|
710
|
+
</button>
|
|
711
|
+
<span class="pdf-toolbar-hint" title="Cmd/Ctrl+click a line in the editor to find it in the PDF">Double-click the PDF to jump to its source</span>
|
|
712
|
+
</div>
|
|
713
|
+
<div id="pdf-pages"></div>
|
|
714
|
+
<iframe id="pdf-fallback" class="hidden" title="PDF preview"></iframe>
|
|
715
|
+
<div id="pdf-empty" class="pdf-empty">Compile to see the PDF here.</div>
|
|
716
|
+
</div>
|
|
624
717
|
<div class="resizer resizer-v" id="resizer-versions" title="Resize versions panel"></div>
|
|
625
718
|
<aside id="versions-panel" class="hidden" aria-hidden="true" aria-label="Version history">
|
|
626
719
|
<div class="versions-header">
|
|
@@ -10,6 +10,7 @@ import { getMainFile } from "../editor/mainfile.js";
|
|
|
10
10
|
import { refreshProjectIndex } from "../editor/projectindex.js";
|
|
11
11
|
import { saveCurrentFile } from "../editor/session.js";
|
|
12
12
|
import { setConsole } from "../ui/consolepane.js";
|
|
13
|
+
import { pdfUrlFor, showPdf } from "../ui/pdfviewer.js";
|
|
13
14
|
|
|
14
15
|
export function setCompileLoading(loading) {
|
|
15
16
|
const btn = document.getElementById("btn-compile");
|
|
@@ -56,7 +57,7 @@ export async function compile() {
|
|
|
56
57
|
if (isDataUrl) {
|
|
57
58
|
const base64 = pdfStr.includes(",") ? pdfStr.slice(pdfStr.indexOf(",") + 1).trim() : pdfStr;
|
|
58
59
|
if (!base64) {
|
|
59
|
-
|
|
60
|
+
showPdf(data.pdf);
|
|
60
61
|
setConsole("Compiled " + mainFile + " via API.");
|
|
61
62
|
} else {
|
|
62
63
|
const savePayload = { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ path: pdfPath, content: base64 }) };
|
|
@@ -82,21 +83,19 @@ export async function compile() {
|
|
|
82
83
|
}
|
|
83
84
|
try {
|
|
84
85
|
if (saveRes.ok && saveData.success) {
|
|
85
|
-
|
|
86
|
-
const pdfUrl = base + (pdfPath.includes("/") ? "/pdf?path=" + encodeURIComponent(pdfPath) : "/pdf/" + pdfPath);
|
|
87
|
-
document.getElementById("pdf").src = pdfUrl;
|
|
86
|
+
showPdf(pdfUrlFor(pdfPath) + (pdfPath.includes("/") ? "&" : "?") + "t=" + Date.now(), pdfPath);
|
|
88
87
|
setConsole("Compiled " + mainFile + " via API. PDF saved to " + pdfPath);
|
|
89
88
|
} else {
|
|
90
|
-
|
|
89
|
+
showPdf(data.pdf);
|
|
91
90
|
setConsole("Compiled " + mainFile + " via API. Save to repo failed: " + (saveData.error || saveRes.status || "unknown"));
|
|
92
91
|
}
|
|
93
92
|
} catch (e) {
|
|
94
|
-
|
|
93
|
+
showPdf(data.pdf);
|
|
95
94
|
setConsole("Compiled " + mainFile + " via API. Save to repo failed: " + (e.message || "network error"));
|
|
96
95
|
}
|
|
97
96
|
}
|
|
98
97
|
} else {
|
|
99
|
-
|
|
98
|
+
showPdf(data.pdf);
|
|
100
99
|
setConsole("Compiled " + mainFile + " via API.");
|
|
101
100
|
}
|
|
102
101
|
} else if (data.error) {
|
|
@@ -121,7 +120,7 @@ export async function compile() {
|
|
|
121
120
|
applyProblems(data.problems || []);
|
|
122
121
|
if (data.success && data.pdf) {
|
|
123
122
|
// Cache-bust so the viewer shows the freshly built PDF.
|
|
124
|
-
|
|
123
|
+
showPdf((getApiBase() || "") + data.pdf + "?t=" + Date.now(), mainFile.replace(/\.tex$/i, ".pdf"));
|
|
125
124
|
renderProblems(data.problems || [], describeBuild(mainFile, data), data.log);
|
|
126
125
|
} else if (data.error) {
|
|
127
126
|
renderProblems(data.problems || [], "Compile error: " + data.error, data.log);
|