diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6fdd16d9..82edf5cf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,4 @@
+- Fixed markdown preview not rendering images (`` syntax)
- Fixed session tab blocking resize below ~600px when docked as a side panel (https://github.com/nbclaudecodegui/NetbeansClaudeCodeGui/issues/19)
- Fixed terminal appearing blank after dismissing the model selection menu
- Fixed MCP connection to localhost being routed through an active HTTP_PROXY/HTTPS_PROXY; NO_PROXY is now automatically extended with localhost and 127.0.0.1 when a proxy is configured
diff --git a/docs/to-do.md b/docs/to-do.md
index eadc7e77..c23e8a7e 100644
--- a/docs/to-do.md
+++ b/docs/to-do.md
@@ -2,11 +2,11 @@
- [x] **Tooltip "Stop session" → "Close session"** — `ClaudeSessionTab.java:229`: переименовать tooltip кнопки `stopButton` с "Stop session" на "Close session" (кнопка закрывает сессию, а не останавливает процесс).
- [x] **IDE restore не сохраняет режим Resume specific** — `ClaudeSessionTab.writeExternal()` сохраняет значение настройки `contextMenuSessionMode` вместо фактического режима/resumeId, с которым была открыта сессия. Если сессия была открыта через "Resume specific", после рестарта IDE она восстановится в режиме Continue last (или New), а не возобновит ту же конкретную сессию.
-- [ ] Drag and drop in a text field: вставлять в текущую позицию курсора, а не
+- [x] Drag and drop in a text field: вставлять в текущую позицию курсора, а не
сдвигать позицию курсора. Рднако, возможность перемещения позиции курсора кликом должна быть созранена
- [x] Невозможно выйти из /usage по кнопке cancel. Отладить
- [x] Не учитываются цвета Look and Feel для кнопок
-- [ ] Previe markdown: не показываются изображения
+- [x] Previe markdown: не показываются изображения
- [ ] Previe markdown: не работает навигация по линкам внутри файла
# Features
diff --git a/pom.xml b/pom.xml
index 2b676dee..2797a16a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
io.github.nbclaudecodegui
netbeans-claude-code-gui
- 0.21.49-SNAPSHOT
+ 0.21.50-SNAPSHOT
nbm
Netbeans Claude Code GUI
NetBeans plugin that provides a GUI for Claude Code CLI — run claude code sessions directly inside the IDE.
diff --git a/src/main/java/io/github/nbclaudecodegui/ui/MarkdownPreviewTab.java b/src/main/java/io/github/nbclaudecodegui/ui/MarkdownPreviewTab.java
index 1e946dea..777f8fb5 100644
--- a/src/main/java/io/github/nbclaudecodegui/ui/MarkdownPreviewTab.java
+++ b/src/main/java/io/github/nbclaudecodegui/ui/MarkdownPreviewTab.java
@@ -134,7 +134,7 @@ public static void openLive(String filePath, String content, FileObject fo) {
tab.fileObject = fo;
String html = MarkdownRenderer.toHtml(content != null ? content : "");
- tab.pane = MarkdownRenderer.createOutputPane(html);
+ tab.pane = MarkdownRenderer.createOutputPane(html, new java.io.File(filePath).getParent());
String name = new java.io.File(filePath).getName();
tab.setDisplayName("Preview: " + name);
diff --git a/src/main/java/io/github/nbclaudecodegui/ui/common/MarkdownRenderer.java b/src/main/java/io/github/nbclaudecodegui/ui/common/MarkdownRenderer.java
index 246b6f09..90d16086 100644
--- a/src/main/java/io/github/nbclaudecodegui/ui/common/MarkdownRenderer.java
+++ b/src/main/java/io/github/nbclaudecodegui/ui/common/MarkdownRenderer.java
@@ -42,7 +42,8 @@ public final class MarkdownRenderer {
+ "|\\*\\*(.+?)\\*\\*" // group 2: bold
+ "|\\*([^*\\n]+)\\*" // group 3: italic
+ "|`([^`]+)`" // group 4: inline code
- + "|\\[([^\\]]+)\\]\\(([^)]+)\\)", // group 5: link text, group 6: link url
+ + "|!\\[([^\\]]*)\\]\\(([^)]+)\\)" // group 5: image alt, group 6: image src
+ + "|\\[([^\\]]+)\\]\\(([^)]+)\\)", // group 7: link text, group 8: link url
Pattern.DOTALL);
// -------------------------------------------------------------------------
@@ -64,6 +65,28 @@ public static JEditorPane createOutputPane(String html) {
return pane;
}
+ /**
+ * Creates and configures a {@link JEditorPane} with HTML content and a base directory for
+ * resolving relative image paths.
+ *
+ * @param html initial HTML content to display
+ * @param baseDirPath absolute path of the directory containing the rendered file, or null
+ * @return a ready-to-use output pane
+ */
+ public static JEditorPane createOutputPane(String html, String baseDirPath) {
+ JEditorPane pane = createOutputPane();
+ if (baseDirPath != null) {
+ try {
+ ((HTMLDocument) pane.getDocument()).setBase(
+ new java.net.URL("file://" + baseDirPath + "/"));
+ } catch (java.net.MalformedURLException ignored) {
+ // fall through — relative images won't resolve but nothing breaks
+ }
+ }
+ pane.setText(html);
+ return pane;
+ }
+
/**
* Creates and configures a {@link JEditorPane} for rendering chat output with no initial content.
*
@@ -398,8 +421,11 @@ static String inlineToHtml(String text) {
} else if (m.group(4) != null) {
sb.append("").append(esc(m.group(4))).append("");
} else if (m.group(5) != null) {
- sb.append("")
- .append(esc(m.group(5))).append("");
+ sb.append("
");
+ } else if (m.group(7) != null) {
+ sb.append("")
+ .append(esc(m.group(7))).append("");
}
lastEnd = m.end();
}
diff --git a/src/test/java/io/github/nbclaudecodegui/ui/common/MarkdownRendererTest.java b/src/test/java/io/github/nbclaudecodegui/ui/common/MarkdownRendererTest.java
index 12870322..fe383eb4 100644
--- a/src/test/java/io/github/nbclaudecodegui/ui/common/MarkdownRendererTest.java
+++ b/src/test/java/io/github/nbclaudecodegui/ui/common/MarkdownRendererTest.java
@@ -208,4 +208,33 @@ void testTableFollowedByParagraph() {
assertTrue(html.contains("
"), "table present");
assertTrue(html.contains("Some text after"), "paragraph after table");
}
+
+ // -------------------------------------------------------------------------
+ // Bug 2: Images
+ // -------------------------------------------------------------------------
+
+ @Test
+ void testInlineImage() {
+ String result = MarkdownRenderer.inlineToHtml("");
+ assertTrue(result.contains("![]()