From f193025ddd24fb4a63f7ec16877c3bdaff4eb9b8 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Meyer Date: Sun, 17 May 2026 11:58:26 +0200 Subject: [PATCH 1/3] Fix scrollbar not resetting to top on file/tab switch (issue #75) Add scrollToTop() to DocumentTab (calls VirtualizedScrollPane.scrollYToPixel(0)) and invoke it in the tab-selection listener so the editor always returns to the top of the document when switching between open files. Co-Authored-By: Claude Sonnet 4.6 --- src/main/java/MarkNote.java | 1 + src/main/java/ui/DocumentTab.java | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/main/java/MarkNote.java b/src/main/java/MarkNote.java index 1fe4316..99422cb 100644 --- a/src/main/java/MarkNote.java +++ b/src/main/java/MarkNote.java @@ -1057,6 +1057,7 @@ private void setupDocumentTab(DocumentTab tab) { previewPanel.updatePreview(docTab.getFullContent()); previewPanel.setCurrentFile(docTab.getFile()); updateStatusBarForTab(docTab); + docTab.scrollToTop(); } else { statusBar.clearDocumentInfo(); statusBar.updateStats(indexService.getEntries().size(), 0, 0); diff --git a/src/main/java/ui/DocumentTab.java b/src/main/java/ui/DocumentTab.java index 39d1c52..f840396 100644 --- a/src/main/java/ui/DocumentTab.java +++ b/src/main/java/ui/DocumentTab.java @@ -606,6 +606,10 @@ public StyleClassedTextArea getEditor() { return editor; } + public void scrollToTop() { + scrollPane.scrollYToPixel(0); + } + /** * Insère du texte à la ligne suivant la position courante du curseur. * Si l'éditeur n'a pas de focus, le texte est ajouté à la fin du document. From 0c75cf7ade1ba888b4cbfe45ed18826d25117fb9 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Meyer Date: Mon, 18 May 2026 20:30:33 +0200 Subject: [PATCH 2/3] Fix scrollbar sync and reading mode scroll reset (issue #75) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Sync preview scrollbar to editor position on tab switch (normal mode) - Reset preview to top on document switch in reading mode - Guard editor→preview scroll propagation with !readingModeActive to prevent off-screen VirtualizedScrollPane from pushing wrong scroll fractions to the preview Co-Authored-By: Claude Sonnet 4.6 --- .continue/agents/new-config-1.yaml | 23 +++++++++++++++++++++++ .continue/agents/new-config.yaml | 23 +++++++++++++++++++++++ src/main/java/MarkNote.java | 19 ++++++++++++++----- src/main/java/ui/PreviewPanel.java | 30 +++++++++++++++++++++++++++--- 4 files changed, 87 insertions(+), 8 deletions(-) create mode 100644 .continue/agents/new-config-1.yaml create mode 100644 .continue/agents/new-config.yaml diff --git a/.continue/agents/new-config-1.yaml b/.continue/agents/new-config-1.yaml new file mode 100644 index 0000000..d55cdcf --- /dev/null +++ b/.continue/agents/new-config-1.yaml @@ -0,0 +1,23 @@ +# This is an example configuration file +# To learn more, see the full config.yaml reference: https://docs.continue.dev/reference + +name: Example Config +version: 1.0.0 +schema: v1 + +# Define which models can be used +# https://docs.continue.dev/customization/models +models: + - name: my gpt-5 + provider: openai + model: gpt-5 + apiKey: YOUR_OPENAI_API_KEY_HERE + - uses: ollama/qwen2.5-coder-7b + - uses: anthropic/claude-4-sonnet + with: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + +# MCP Servers that Continue can access +# https://docs.continue.dev/customization/mcp-tools +mcpServers: + - uses: anthropic/memory-mcp diff --git a/.continue/agents/new-config.yaml b/.continue/agents/new-config.yaml new file mode 100644 index 0000000..d55cdcf --- /dev/null +++ b/.continue/agents/new-config.yaml @@ -0,0 +1,23 @@ +# This is an example configuration file +# To learn more, see the full config.yaml reference: https://docs.continue.dev/reference + +name: Example Config +version: 1.0.0 +schema: v1 + +# Define which models can be used +# https://docs.continue.dev/customization/models +models: + - name: my gpt-5 + provider: openai + model: gpt-5 + apiKey: YOUR_OPENAI_API_KEY_HERE + - uses: ollama/qwen2.5-coder-7b + - uses: anthropic/claude-4-sonnet + with: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + +# MCP Servers that Continue can access +# https://docs.continue.dev/customization/mcp-tools +mcpServers: + - uses: anthropic/memory-mcp diff --git a/src/main/java/MarkNote.java b/src/main/java/MarkNote.java index 99422cb..1e3ccf1 100644 --- a/src/main/java/MarkNote.java +++ b/src/main/java/MarkNote.java @@ -1034,8 +1034,9 @@ private void setupDocumentTab(DocumentTab tab) { previewDebouncer.debounce(() -> { Platform.runLater(() -> { previewPanel.updatePreview(text); - // Realigner la preview avec la position actuelle de l'éditeur - if (editorSplit.getItems().contains(previewPanel)) { + // Realigner la preview sur l'éditeur, mais pas en reading mode + // (l'éditeur est hors-scène, getScrollFraction() peut être faux) + if (!readingModeActive && editorSplit.getItems().contains(previewPanel)) { previewPanel.scrollToFraction(tab.getScrollFraction()); } updateStatusBarForTab(tab); @@ -1054,19 +1055,27 @@ private void setupDocumentTab(DocumentTab tab) { // Mettre à jour la preview et la statusbar quand on change d'onglet mainTabPane.getSelectionModel().selectedItemProperty().addListener((obs, oldTab, newTab) -> { if (newTab instanceof DocumentTab docTab) { + if (readingModeActive) { + // En mode lecture : remettre la scrollbar à zéro sur le nouveau document + docTab.scrollToTop(); + previewPanel.scrollToFractionAfterLoad(0.0); + } else { + // En mode normal : synchroniser la preview sur la position de l'éditeur + previewPanel.scrollToFractionAfterLoad(docTab.getScrollFraction()); + } previewPanel.updatePreview(docTab.getFullContent()); previewPanel.setCurrentFile(docTab.getFile()); updateStatusBarForTab(docTab); - docTab.scrollToTop(); } else { statusBar.clearDocumentInfo(); statusBar.updateStats(indexService.getEntries().size(), 0, 0); } }); - // Synchroniser le défilement éditeur → preview + // Synchroniser le défilement éditeur → preview (pas en reading mode : éditeur hors-scène) tab.setOnScrollFractionChanged(fraction -> { - if (mainTabPane.getSelectionModel().getSelectedItem() == tab + if (!readingModeActive + && mainTabPane.getSelectionModel().getSelectedItem() == tab && editorSplit.getItems().contains(previewPanel)) { previewPanel.scrollToFraction(fraction); } diff --git a/src/main/java/ui/PreviewPanel.java b/src/main/java/ui/PreviewPanel.java index c7321f8..cc5f13b 100644 --- a/src/main/java/ui/PreviewPanel.java +++ b/src/main/java/ui/PreviewPanel.java @@ -89,6 +89,9 @@ public class PreviewPanel extends BasePanel { /** Fichier source Markdown courant (peut être null pour les documents non sauvegardés). */ private File currentFile; + /** Fraction de défilement à appliquer après le prochain chargement de page. */ + private Double pendingScrollFraction = null; + /** Thème highlight.js courant, synchronisé avec le thème applicatif. */ private SyntaxTheme syntaxTheme = new SyntaxTheme("github", "#f6f8fa", "#24292e"); @@ -215,9 +218,19 @@ public PreviewPanel() { } } } - } else if (newState == Worker.State.SUCCEEDED && !pendingLocalPumlBlocks.isEmpty()) { - // Page chargée : déclencher le rendu async des blocs PlantUML locaux - dispatchLocalPumlRendering(); + } else if (newState == Worker.State.SUCCEEDED) { + // Page chargée : appliquer le scroll en attente si défini + if (pendingScrollFraction != null) { + double fraction = pendingScrollFraction; + pendingScrollFraction = null; + webView.getEngine().executeScript( + "window.scrollTo(0, (document.body.scrollHeight - window.innerHeight) * " + fraction + ")" + ); + } + // Déclencher le rendu async des blocs PlantUML locaux + if (!pendingLocalPumlBlocks.isEmpty()) { + dispatchLocalPumlRendering(); + } } }); @@ -1127,6 +1140,17 @@ public void scrollToFraction(double fraction) { ); } } + + /** + * Planifie un défilement vers la fraction donnée après le prochain chargement de page. + * À utiliser juste avant ou juste après {@link #updatePreview(String)} lors d'un changement + * de document, quand le WebView n'a pas encore terminé de charger le nouveau contenu. + * + * @param fraction La fraction de défilement dans [0.0, 1.0] + */ + public void scrollToFractionAfterLoad(double fraction) { + this.pendingScrollFraction = Math.min(1.0, Math.max(0.0, fraction)); + } /** * Définit le fichier Markdown source actuellement affiché. From 54b7cd7264214e2766cd658befc02ae4fee1de72 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Meyer Date: Mon, 18 May 2026 20:35:16 +0200 Subject: [PATCH 3/3] Update Continue agent config with Ollama QwenCoder 32B model Co-Authored-By: Claude Sonnet 4.6 --- .continue/agents/new-config-1.yaml | 23 --------------- .continue/agents/new-config.yaml | 45 ++++++++++++++++++------------ 2 files changed, 27 insertions(+), 41 deletions(-) delete mode 100644 .continue/agents/new-config-1.yaml diff --git a/.continue/agents/new-config-1.yaml b/.continue/agents/new-config-1.yaml deleted file mode 100644 index d55cdcf..0000000 --- a/.continue/agents/new-config-1.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# This is an example configuration file -# To learn more, see the full config.yaml reference: https://docs.continue.dev/reference - -name: Example Config -version: 1.0.0 -schema: v1 - -# Define which models can be used -# https://docs.continue.dev/customization/models -models: - - name: my gpt-5 - provider: openai - model: gpt-5 - apiKey: YOUR_OPENAI_API_KEY_HERE - - uses: ollama/qwen2.5-coder-7b - - uses: anthropic/claude-4-sonnet - with: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - -# MCP Servers that Continue can access -# https://docs.continue.dev/customization/mcp-tools -mcpServers: - - uses: anthropic/memory-mcp diff --git a/.continue/agents/new-config.yaml b/.continue/agents/new-config.yaml index d55cdcf..5caf2a7 100644 --- a/.continue/agents/new-config.yaml +++ b/.continue/agents/new-config.yaml @@ -1,23 +1,32 @@ -# This is an example configuration file -# To learn more, see the full config.yaml reference: https://docs.continue.dev/reference - -name: Example Config +name: Local Config version: 1.0.0 schema: v1 -# Define which models can be used -# https://docs.continue.dev/customization/models models: - - name: my gpt-5 - provider: openai - model: gpt-5 - apiKey: YOUR_OPENAI_API_KEY_HERE - - uses: ollama/qwen2.5-coder-7b - - uses: anthropic/claude-4-sonnet - with: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + - name: Qwen Coder 32B + provider: ollama + model: qwen2.5-coder:32b + apiBase: http://localhost:11434 + roles: + - chat + - edit + - apply + + - name: Qwen Coder Autocomplete + provider: ollama + model: qwen2.5-coder:1.5b-base + apiBase: http://localhost:11434 + roles: + - autocomplete + + - name: Nomic Embed + provider: ollama + model: nomic-embed-text:latest + apiBase: http://localhost:11434 + roles: + - embed -# MCP Servers that Continue can access -# https://docs.continue.dev/customization/mcp-tools -mcpServers: - - uses: anthropic/memory-mcp +context: + - provider: code + - provider: docs + - provider: diff