Skip to content

Conversation

@lucolvin
Copy link
Contributor

@lucolvin lucolvin commented Jan 7, 2026

Greptile Overview

Greptile Summary

This PR reintroduces CodeMirror as the code editor for mobile and touch devices while preserving Monaco for desktop users. The implementation conditionally renders editors based on device capabilities.

Key changes:

  • Added CodeMirror dependencies (@codemirror/* packages) to support mobile editing
  • Created new CodeMirror editor component with YAML linting, auto-height support, and proper Svelte 5 state management
  • Implemented dynamic theming system that reads CSS variables to match the app's accent colors
  • Modified CodePanel.svelte to detect mobile/touch devices and switch between editors accordingly
  • Added Vite deduplication config for CodeMirror packages to prevent version conflicts

Issues found:

  • SSR bug in theme.ts: accessing document without browser environment check will cause server-side rendering failures
  • Code duplication: touch detection logic is reimplemented instead of using the existing IsTouchDevice hook

Confidence Score: 3/5

  • This PR has a critical SSR bug that will break server-side rendering
  • Score reflects one critical logic error (SSR bug accessing document without checks) that will cause runtime failures during server-side rendering, plus minor code duplication. The SSR issue must be fixed before merging to prevent build/deployment failures.
  • Pay close attention to frontend/src/lib/components/codemirror-code-editor/theme.ts - the SSR bug will cause failures

Important Files Changed

File Analysis

Filename Score Overview
frontend/src/lib/components/codemirror-code-editor/editor.svelte 5/5 implemented CodeMirror editor with YAML linting, proper state management, and auto-height support
frontend/src/lib/components/codemirror-code-editor/theme.ts 2/5 created theme utilities for CodeMirror with dynamic accent colors - has SSR bug accessing document without browser check
frontend/src/routes/(app)/projects/components/CodePanel.svelte 4/5 conditionally renders CodeMirror on mobile/touch devices and Monaco on desktop - has code duplication for touch detection
frontend/vite.config.ts 5/5 added CodeMirror package deduplication to resolve dependency conflicts

Disclaimer Greptiles Reviews use AI, make sure to check over its work

Greptile Overview

Greptile Summary

This PR reintroduces CodeMirror as the mobile/touch editor while keeping Monaco for desktop, addressing mobile editor functionality issues. The implementation adds comprehensive CodeMirror support with YAML linting, dynamic theming, and proper Svelte 5 integration.

Changes Overview

New CodeMirror Implementation:

  • Created codemirror-code-editor/editor.svelte with YAML/env language support, linting via js-yaml, and auto-height functionality
  • Built codemirror-code-editor/theme.ts with dynamic color system that reads CSS variables to match app accent colors
  • Properly implemented Svelte 5 runes ($state, $effect, $bindable) for reactive state management

Device Detection & Routing:

  • Modified CodePanel.svelte to conditionally render CodeMirror for mobile/touch devices and Monaco for desktop
  • Uses existing IsMobile and IsTouchDevice hooks for device detection

Monaco Editor Updates:

  • Changed fixedOverflowWidgets from true to false to allow suggestion widgets to overflow card boundaries
  • Added selectionClipboard: true for middle-click paste support on Linux
  • Coordinated CSS changes in app.css to handle Monaco widget positioning

Build Configuration:

  • Added Vite deduplication for CodeMirror packages to prevent version conflicts

Critical Issue Found

Permission Bypass on Mobile (MUST FIX): The readOnly prop is not passed to MobileCodeEditor in CodePanel.svelte line 44. Since readOnly is used to enforce edit permissions based on canEditCompose (see [projectId]/+page.svelte lines 494, 559), mobile/touch users can edit content even when they lack permission. This is a security/permission control issue.

Style Issues

Multiple visual inconsistencies between CodeMirror and Monaco editors:

  • Font size defaults: CodeMirror defaults to 13px vs Monaco's 12px
  • Font family: CodeMirror uses "Geist Mono" as primary font, Monaco doesn't include it
  • Padding: CodeMirror uses 12px uniform padding vs Monaco's 10px top/bottom only
  • Redundant code: Math.max in yaml linter is unnecessary (line 44 of editor.svelte)

These inconsistencies mean the editor will look and feel different when switching between desktop and mobile devices viewing the same content.

Technical Implementation Quality

Strengths:

  • Proper SSR handling with browser environment checks in theme.ts
  • Clean Svelte 5 runes usage throughout
  • Comprehensive YAML linting with proper error positioning
  • Good separation of concerns (theme, editor, panel logic)
  • Proper cleanup in onDestroy lifecycle hooks

Note on "SSR Bug" Claim: The PR description mentions an SSR bug in theme.ts accessing document without checks, but the code actually has proper guards (typeof document === 'undefined') and the function is only called in onMount which is browser-only. The SSR concern appears to be unfounded.

Testing Recommendations

  1. Test edit permissions on mobile/touch devices after fixing the readOnly prop
  2. Verify visual consistency between CodeMirror and Monaco renders
  3. Test touch interactions with YAML linting errors
  4. Verify theme switching works correctly on mobile
  5. Test auto-height behavior across different content sizes

Confidence Score: 2/5

  • This PR has a critical permission bypass bug that must be fixed before merging
  • Score of 2/5 reflects one critical logic error (missing readOnly prop on mobile editor) that creates a permission bypass allowing unauthorized editing on mobile/touch devices. Additionally, there are multiple style inconsistencies between the CodeMirror and Monaco editors (font sizes, font families, padding) that will create jarring visual differences when users switch between desktop and mobile. The core implementation is sound with proper SSR handling and clean Svelte 5 code, but the permission bug is a security concern that blocks safe merging.
  • Critical attention required: frontend/src/routes/(app)/projects/components/CodePanel.svelte (must add readOnly prop). Secondary attention: editor styling consistency across frontend/src/lib/components/codemirror-code-editor/editor.svelte and theme.ts

Important Files Changed

File Analysis

Filename Score Overview
frontend/src/lib/components/codemirror-code-editor/editor.svelte 4/5 New CodeMirror editor with YAML linting and Svelte 5 state management - has minor style issues (redundant Math.max, font size default inconsistency, padding differences)
frontend/src/lib/components/codemirror-code-editor/theme.ts 4/5 Dynamic theme system with CSS variable integration and proper SSR guards - has font family inconsistency with Monaco editor
frontend/src/lib/components/monaco-code-editor/editor.svelte 5/5 Updated Monaco config to fix widget overflow and enable selection clipboard - changes are intentional and properly coordinated with CSS
frontend/src/routes/(app)/projects/components/CodePanel.svelte 2/5 Implements conditional editor rendering for mobile/touch devices - CRITICAL: missing readOnly prop causes permission bypass on mobile
frontend/vite.config.ts 5/5 Added CodeMirror package deduplication to prevent version conflicts - follows best practices

@lucolvin lucolvin requested a review from a team January 7, 2026 12:51
@kmendell
Copy link
Member

kmendell commented Jan 7, 2026

Id rather not have two different editors as both of these are huge dependencies, and the netire frontnend is embeded in the go biniary which shouldnt be an issue but can make the biannry bigger.

I have looked into the editor issues yet , but theys should be solve able with the monaco one on mobile id think?

@lucolvin
Copy link
Contributor Author

lucolvin commented Jan 7, 2026

Thats fair. I poked around Monaco a bit trying to find a fix and apparently its a known issue on mobile. I was just tired of not being able to use mobile to edit so I chose this.

@lucolvin lucolvin closed this Jan 7, 2026
@kmendell
Copy link
Member

kmendell commented Jan 7, 2026

I'll do some digging I've had to hack some stuff up to get get Monaco to work for the auto completions (that's why I switched to it), ill see what I can figure out

@kmendell kmendell reopened this Jan 8, 2026
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

@github-actions
Copy link

github-actions bot commented Jan 8, 2026

This pull request has merge conflicts. Please resolve the conflicts so the PR can stay up-to-date and reviewed.

@lucolvin lucolvin changed the title fix: reintroduce code-mirror editor on mobile fix: editor issues on mobile Jan 8, 2026
@lucolvin
Copy link
Contributor Author

lucolvin commented Jan 8, 2026

@kmendell Quick question. You said you switched from code mirror to monaco for autocompletion support. Code mirror 6 has auto-completion and better mobile support. What are your thoughts about fully reverting to code mirror and dropping monaco? Or was the change away from code mirror an attempt to reduce dependencies as it has more packages?

@kmendell
Copy link
Member

kmendell commented Jan 8, 2026

@kmendell Quick question. You said you switched from code mirror to monaco for autocompletion support. Code mirror 6 has auto-completion and better mobile support. What are your thoughts about fully reverting to code mirror and dropping monaco? Or was the change away from code mirror an attempt to reduce dependencies as it has more packages?

There was more to it the auto completion with monaco i can grab the latest compose spec and have that used as auto completion i never got it to work with code mirror. Also the svelte-codemirror package did not like me setting a static height for it , like the monaco ones are now, which i think looks alot cleaner than the editors only being as tall as the content.

Overall monaco and code-mirror are both heavy deps. But monaco does have less packages, its possible to fix all of these issues with monaco im fairly confident you just have to do some hacky stuff.

@kmendell
Copy link
Member

kmendell commented Jan 9, 2026

i suppose this is the easiest way to do this....

@lucolvin
Copy link
Contributor Author

lucolvin commented Jan 9, 2026

i suppose this is the easiest way to do this....

I have been messing around with having an invisible overlay on mobile that allows for native interaction with monaco. It works but its not perfect.

@kmendell
Copy link
Member

kmendell commented Jan 9, 2026

Oh i mean feel free to keep working on it. But since mobile is a big focus of why people like arcane i guess bringing back code mirror is a bandaid fix. At least so its useable.

@lucolvin
Copy link
Contributor Author

lucolvin commented Jan 9, 2026

Oh i mean feel free to keep working on it. But since mobile is a big focus of why people like arcane i guess bringing back code mirror is a bandaid fix. At least so its useable.

That was my thinking when I added it back. I also looked into ace which could be an alternative.

Copy link
Member

kmendell commented Jan 9, 2026

Honestly im not set on either or, i just didn't want to bloated deps in the binary. Do what you think is best, a requirement i think though is keeping that auto completion based on the compose spec.

@lucolvin lucolvin changed the title fix: editor issues on mobile fix: editor issues on mobile. Temp fix #1365 Jan 10, 2026
@lucolvin
Copy link
Contributor Author

@kmendell I re-pushed the code-mirror addition. I will continue working on a more permanent fix. I think it is totally possible to get monaco working for mobile but it will take some work.

@kmendell
Copy link
Member

@greptileai

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

6 files reviewed, 6 comments

Edit Code Review Agent Settings | Greptile

} catch (e: unknown) {
const err = e as { mark?: { position: number }; message?: string };
const start = err.mark?.position || 0;
const end = err.mark?.position !== undefined ? Math.max(start + 1, err.mark.position + 1) : start + 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Math.max call is redundant here since both arguments evaluate to the same value when err.mark.position is defined.

When err.mark?.position exists, start is already set to err.mark.position (line 43), so this becomes Math.max(err.mark.position + 1, err.mark.position + 1), which is just err.mark.position + 1. Consider simplifying:

Suggested change
const end = err.mark?.position !== undefined ? Math.max(start + 1, err.mark.position + 1) : start + 1;
const end = err.mark?.position !== undefined ? start + 1 : start + 1;
Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src/lib/components/codemirror-code-editor/editor.svelte
Line: 44:44

Comment:
The `Math.max` call is redundant here since both arguments evaluate to the same value when `err.mark.position` is defined.

When `err.mark?.position` exists, `start` is already set to `err.mark.position` (line 43), so this becomes `Math.max(err.mark.position + 1, err.mark.position + 1)`, which is just `err.mark.position + 1`. Consider simplifying:

```suggestion
			const end = err.mark?.position !== undefined ? start + 1 : start + 1;
```

How can I resolve this? If you propose a fix, please make it concise.

value = $bindable(''),
language = 'yaml' as CodeLanguage,
readOnly = false,
fontSize = '13px',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Font size default inconsistency: CodeMirror defaults to '13px' while Monaco defaults to '12px' (monaco-code-editor/editor.svelte line 14). Since both editors are used interchangeably in CodePanel for the same content, they should have matching defaults to ensure consistent appearance across devices.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src/lib/components/codemirror-code-editor/editor.svelte
Line: 20:20

Comment:
Font size default inconsistency: CodeMirror defaults to '13px' while Monaco defaults to '12px' (monaco-code-editor/editor.svelte line 14). Since both editors are used interchangeably in CodePanel for the same content, they should have matching defaults to ensure consistent appearance across devices.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +52 to +53
fontFamily:
'"Geist Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Font family inconsistency: CodeMirror includes "Geist Mono" as the primary font, but Monaco editor (monaco-code-editor/editor.svelte line 115) uses 'ui-monospace' as primary and doesn't include "Geist Mono" at all. Since these editors display the same content on different devices, consider aligning the font stacks for visual consistency.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src/lib/components/codemirror-code-editor/theme.ts
Line: 52:53

Comment:
Font family inconsistency: CodeMirror includes "Geist Mono" as the primary font, but Monaco editor (monaco-code-editor/editor.svelte line 115) uses 'ui-monospace' as primary and doesn't include "Geist Mono" at all. Since these editors display the same content on different devices, consider aligning the font stacks for visual consistency.

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

fontSize: size
},
'.cm-content': {
padding: '12px'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Padding inconsistency between editors: CodeMirror uses 12px padding while Monaco uses padding: { top: 10, bottom: 10 } (monaco-code-editor/editor.svelte line 117). This creates a different visual appearance when switching between desktop and mobile. Consider standardizing the padding values.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src/lib/components/codemirror-code-editor/editor.svelte
Line: 73:73

Comment:
Padding inconsistency between editors: CodeMirror uses 12px padding while Monaco uses `padding: { top: 10, bottom: 10 }` (monaco-code-editor/editor.svelte line 117). This creates a different visual appearance when switching between desktop and mobile. Consider standardizing the padding values.

How can I resolve this? If you propose a fix, please make it concise.

} = $props();
const isMobile = new IsMobile();
const isTouchDevice = new IsTouchDevice();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The IsTouchDevice hook is already imported but you're also checking isMobile.current separately. On most mobile devices, both would be true (mobile screen size + touch capability), making the check somewhat redundant. Consider documenting why both checks are needed, or if the intent is to support desktop devices with touchscreens (like Surface devices), the current logic is correct.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src/routes/(app)/projects/components/CodePanel.svelte
Line: 30:30

Comment:
The `IsTouchDevice` hook is already imported but you're also checking `isMobile.current` separately. On most mobile devices, both would be true (mobile screen size + touch capability), making the check somewhat redundant. Consider documenting why both checks are needed, or if the intent is to support desktop devices with touchscreens (like Surface devices), the current logic is correct.

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

@kmendell
Copy link
Member

@lucolvin See this c5a5c8a#diff-9a9751527e826ccdd1ddd4239030e98de6c8614b1cd53f3e8e63bbcd8f381fee. Thats when i removed it, i see some inconsistencies with what i had before vs what you have now,

@github-actions
Copy link

This pull request has merge conflicts. Please resolve the conflicts so the PR can stay up-to-date and reviewed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants