summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/index.ts3
-rw-r--r--src/renderer/src/components/Editor.tsx7
-rw-r--r--src/renderer/src/components/ProjectList.tsx2
-rw-r--r--src/renderer/src/components/Terminal.tsx5
-rw-r--r--src/renderer/src/extensions/commentHighlights.ts1
-rw-r--r--src/renderer/src/ot/overleafSync.ts28
-rw-r--r--src/renderer/src/stores/appStore.ts5
7 files changed, 39 insertions, 12 deletions
diff --git a/src/main/index.ts b/src/main/index.ts
index 7fab07a..0925c01 100644
--- a/src/main/index.ts
+++ b/src/main/index.ts
@@ -664,7 +664,8 @@ ipcMain.handle('ot:connect', async (_e, projectId: string) => {
docPathMap,
pathDocMap,
fileRefs,
- rootFolderId
+ rootFolderId,
+ syncDir: tmpDir
}
} catch (e) {
console.log('[ot:connect] error:', e)
diff --git a/src/renderer/src/components/Editor.tsx b/src/renderer/src/components/Editor.tsx
index 649b238..4328c22 100644
--- a/src/renderer/src/components/Editor.tsx
+++ b/src/renderer/src/components/Editor.tsx
@@ -32,9 +32,10 @@ const cosmicLatteTheme = EditorView.theme({
color: '#3B3228', padding: '8px 0'
},
'.cm-cursor': { borderLeftColor: '#3B3228' },
- '.cm-activeLine': { backgroundColor: '#F5EDD6' },
- '.cm-activeLineGutter': { backgroundColor: '#F5EDD6' },
- '.cm-selectionBackground, ::selection': { backgroundColor: '#B8D4E3 !important' },
+ '.cm-activeLine': { backgroundColor: 'rgba(214, 206, 188, 0.3)' },
+ '.cm-activeLineGutter': { backgroundColor: 'rgba(214, 206, 188, 0.3)' },
+ '.cm-selectionBackground, ::selection': { backgroundColor: 'rgba(120, 170, 210, 0.45) !important' },
+ '&.cm-focused .cm-selectionBackground': { backgroundColor: 'rgba(120, 170, 210, 0.45) !important' },
'.cm-gutters': {
backgroundColor: '#F5EDD6', color: '#A09880', border: 'none',
borderRight: '1px solid #D6CEBC', paddingRight: '8px'
diff --git a/src/renderer/src/components/ProjectList.tsx b/src/renderer/src/components/ProjectList.tsx
index d5b382c..a3c9c37 100644
--- a/src/renderer/src/components/ProjectList.tsx
+++ b/src/renderer/src/components/ProjectList.tsx
@@ -65,6 +65,8 @@ export default function ProjectList({ onOpenProject }: Props) {
if (result.fileRefs) store.setFileRefs(result.fileRefs)
if (result.rootFolderId) store.setRootFolderId(result.rootFolderId)
store.setOverleafProjectId(pid)
+ store.setConnectionState('connected')
+ if (result.syncDir) store.setSyncDir(result.syncDir)
setStatusMessage('Connected')
onOpenProject(pid)
} else {
diff --git a/src/renderer/src/components/Terminal.tsx b/src/renderer/src/components/Terminal.tsx
index 3781a53..e2eb5e8 100644
--- a/src/renderer/src/components/Terminal.tsx
+++ b/src/renderer/src/components/Terminal.tsx
@@ -55,8 +55,9 @@ export default function Terminal() {
xtermRef.current = xterm
fitAddonRef.current = fitAddon
- // Spawn shell
- window.api.ptySpawn('/tmp')
+ // Spawn shell in project sync directory
+ const syncDir = useAppStore.getState().syncDir || '/tmp'
+ window.api.ptySpawn(syncDir)
// Pipe data
const unsubData = window.api.onPtyData((data) => {
diff --git a/src/renderer/src/extensions/commentHighlights.ts b/src/renderer/src/extensions/commentHighlights.ts
index 3215026..8ea1cd7 100644
--- a/src/renderer/src/extensions/commentHighlights.ts
+++ b/src/renderer/src/extensions/commentHighlights.ts
@@ -220,7 +220,6 @@ const commentHighlightTheme = EditorView.baseTheme({
backgroundColor: 'rgba(243, 177, 17, 0.25)',
borderBottom: '2px solid rgba(243, 177, 17, 0.5)',
padding: '1px 0',
- cursor: 'pointer',
},
'.cm-comment-highlight-hover': {
backgroundColor: 'rgba(243, 177, 17, 0.45)',
diff --git a/src/renderer/src/ot/overleafSync.ts b/src/renderer/src/ot/overleafSync.ts
index 787a458..1c6672b 100644
--- a/src/renderer/src/ot/overleafSync.ts
+++ b/src/renderer/src/ot/overleafSync.ts
@@ -3,7 +3,8 @@
// Per-document orchestrator: ties CM6 adapter to OT client, IPC bridge
import type { EditorView } from '@codemirror/view'
-import { ChangeSet, Transaction, type Text } from '@codemirror/state'
+import { ChangeSet, Transaction, type ChangeSpec, type Text } from '@codemirror/state'
+import { diff_match_patch } from 'diff-match-patch'
import { OtClient } from './otClient'
import type { OtOp } from './types'
import { changeSetToOtOps, otOpsToChangeSpec } from './cmAdapter'
@@ -136,10 +137,27 @@ export class OverleafDocSync {
const currentContent = this.view.state.doc.toString()
if (currentContent === newContent) return
- // Dispatch as a local change (NOT remote annotation) so it flows through OT
- this.view.dispatch({
- changes: { from: 0, to: this.view.state.doc.length, insert: newContent }
- })
+ // Use diff to compute minimal changes so comment range positions remap correctly
+ const dmp = new diff_match_patch()
+ const diffs = dmp.diff_main(currentContent, newContent)
+ dmp.diff_cleanupEfficiency(diffs)
+
+ const changes: ChangeSpec[] = []
+ let pos = 0
+ for (const [type, text] of diffs) {
+ if (type === 0) { // EQUAL
+ pos += text.length
+ } else if (type === -1) { // DELETE
+ changes.push({ from: pos, to: pos + text.length })
+ pos += text.length
+ } else if (type === 1) { // INSERT
+ changes.push({ from: pos, to: pos, insert: text })
+ }
+ }
+
+ if (changes.length > 0) {
+ this.view.dispatch({ changes })
+ }
}
destroy() {
diff --git a/src/renderer/src/stores/appStore.ts b/src/renderer/src/stores/appStore.ts
index 9e1e141..adb4957 100644
--- a/src/renderer/src/stores/appStore.ts
+++ b/src/renderer/src/stores/appStore.ts
@@ -90,6 +90,8 @@ interface AppState {
setFileRefs: (refs: Array<{ id: string; path: string }>) => void
rootFolderId: string
setRootFolderId: (id: string) => void
+ syncDir: string
+ setSyncDir: (dir: string) => void
// Review panel
showReviewPanel: boolean
@@ -198,6 +200,8 @@ export const useAppStore = create<AppState>((set) => ({
setFileRefs: (refs) => set({ fileRefs: refs }),
rootFolderId: '',
setRootFolderId: (id) => set({ rootFolderId: id }),
+ syncDir: '',
+ setSyncDir: (dir) => set({ syncDir: dir }),
showReviewPanel: false,
toggleReviewPanel: () => set((s) => ({ showReviewPanel: !s.showReviewPanel })),
@@ -240,6 +244,7 @@ export const useAppStore = create<AppState>((set) => ({
overleafProject: null,
fileRefs: [],
rootFolderId: '',
+ syncDir: '',
commentContexts: {},
overleafDocs: {},
hoveredThreadId: null,