Skip to content

feat: add pinch-to-zoom support to editor - #2963

Open
gahanad wants to merge 15 commits into
Acode-Foundation:mainfrom
gahanad:feat/editor-pinch-to-zoom
Open

gahanad wants to merge 15 commits into
Acode-Foundation:mainfrom
gahanad:feat/editor-pinch-to-zoom

Conversation

@gahanad

@gahanad gahanad commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Description

Adds pinch-to-zoom support to the editor to make editing more convenient on mobile devices.

Users can adjust the editor's font size using a two-finger pinch gesture, improving readability and usability on smaller screens.

Changes Made

  • Added a pinch-to-zoom extension for the editor.
  • Dynamically adjusts the editor font size based on the pinch gesture.
  • Enforces minimum and maximum font-size limits.
  • Saves the updated font size setting when the gesture ends.
  • Cleans up touch event listeners when the extension is destroyed.
  • Added unit tests covering pinch-zoom behavior and font-size calculations.

Testing

  • Added unit tests for pinch-zoom functionality.
  • Verified the targeted unit tests pass.
  • Manually tested pinch-to-zoom on an Android device.
  • Verified the full test suite and CI checks.

Related Issue

Closes #2426

@github-actions github-actions Bot added the enhancement New feature or request label Oct 9, 2026
@greptile-apps

greptile-apps Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge, with a non-blocking pinch recovery bug and the earlier saved-preset issue still open.

Findings

  1. P2 New pinch uses old distance ▶
  2. P2 Saved presets change shape ▶

Summary

Adds pinch-to-zoom to the main editor.

  • Two fingers on the editor now change and save its font size.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Two fingers touch editor] --> B[Record fingers and starting size]
  B --> C[Watch movement on document]
  C --> D{Movement held long enough?}
  D -->|Yes| E[Preview bounded font size]
  D -->|No| C
  E --> F[Finger lifts]
  F --> G[Apply latest distance]
  G --> H[Clear preview and save setting]
Loading

Reviews (8) · Last reviewed commit: "Merge upstream main into editor pinch zo..." · Reviewed by Greptile

Comment thread src/cm/pinchZoom.ts Outdated
Comment thread src/cm/pinchZoom.ts Outdated
Comment thread src/cm/pinchZoom.ts Outdated
Comment thread src/cm/pinchZoom.ts Outdated
@gahanad

This comment was marked as outdated.

Comment thread src/cm/pinchZoom.ts Outdated
@gahanad

This comment was marked as outdated.

Comment thread src/cm/pinchZoom.ts Outdated
@gahanad

This comment was marked as outdated.

@bajrangCoder

bajrangCoder commented Oct 11, 2026 •

Copy link
Copy Markdown
Member

There several accidental zoom in/zoom out

screen-20261011-164227.mp4

Comment thread src/cm/pinchZoom.ts Outdated
Comment thread src/cm/pinchZoom.ts Outdated
Comment thread src/cm/pinchZoom.ts Outdated
Comment thread src/cm/pinchZoom.ts Outdated
Comment thread src/cm/pinchZoom.ts Outdated
Comment thread src/cm/pinchZoom.ts Outdated
Comment thread src/cm/pinchZoom.ts Outdated
Comment thread src/cm/pinchZoom.ts Outdated
Comment thread src/cm/mainEditorExtensions.ts Outdated
@gahanad

This comment was marked as outdated.

Comment thread src/cm/pinchZoom.ts
Comment thread src/cm/touchSelectionMenu.js Outdated
@gahanad

gahanad commented Oct 13, 2026

Copy link
Copy Markdown
Contributor Author

@greptile

@gahanad
gahanad requested a review from bajrangCoder October 13, 2026 21:32
Comment thread src/cm/pinchZoom.ts
persistFontSize();
}

const target = view.contentDOM;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Touch events keep targeting the element where each finger first landed, even after that element is removed from the DOM. Since move/end/cancel are only listened for on contentDOM, the gesture can get stuck:

  1. Two fingers start on lines in the lower part of the editor; spread to ~2x.
  2. The preview font change + requestMeasure() makes CM recompute a smaller viewport (visible area + ~500px margin), and the .cm-line under a finger is unmounted.
  3. That finger's touchmove/touchend now dispatch to a detached node and never reach contentDOM.

Result: gesture.pinching stays true, the inline preview is never cleared or persisted, and every subsequent two-finger touchstart bails on if (gesture.pinching ...) — pinch is dead until the editor state is swapped.

Suggest attaching the move/end/cancel listeners to window/document (capture) when a pinch starts and removing them in endPinch/destroy.

@bajrangCoder

Copy link
Copy Markdown
Member

Also isn't the line number area and editor area pinch-to-zoom at same time for better and smooth feel? as currently line number area adjusted itself after leaving zoom.

Also in some cases some accidental scrolls maybe using three finger/two finger etc does nothing but normally in acode those just scrolls so removing that will be a bit weird(if there is no valid reason)

dependabot Bot and others added 5 commits October 16, 2026 02:45
…on#2961)

Bumps ghcr.io/devcontainers/features/node from 2.1.0 to 2.1.1.

---
updated-dependencies:
- dependency-name: ghcr.io/devcontainers/features/node
  dependency-version: 2.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Updated Discord badge URL to a new endpoint.
…e-Foundation#2966)

* refactor(browser): keep a list of devices in the emulator device list

* refactor(browser): register each device when added to the list

* feat(browser): apply the saved default preview size once layout is ready

* feat(browser): save and restore a default device preview size

* feat(browser): add "Set as Default" and "Clear Default" menu items

* feat(browser): handle "Set as Default" and "Clear Default" actions

* feat(browser): show default menu items only while Devices mode is on

* feat(browser): open the preview in Devices mode when a default is set

* feat(browser): restore the default preview mode on startup

* refactor(browser): allow applying desktop mode without reloading

* refactor(browser): make the reload in setDesktopMode optional

* fix(browser): apply saved desktop mode before the first load to avoid a reload

* fix(browser): only apply dimensions after layout, not desktop mode

* fix(browser): re-fit saved presets to the current screen on restore

* fix(browser): reload once after the saved size is applied

* fix(browser): don't resize the webview before the emulator is set up

* fix(browser): add reloadAfterLayout helper, only when a page was requested

* fix(browser): show "Clear Default" only when a default is saved

* fix(browser): refresh default menu items after Set as Default

* fix(browser): refresh default menu items after Clear Default
@gahanad

gahanad commented Oct 18, 2026

Copy link
Copy Markdown
Contributor Author

@greptile

Comment thread tests/unit/pinchZoom.test.ts
scaleSeekBar.getMax()
);
scaleSeekBar.setProgress(scale);
listener.onChange(getWidthProgress(), getHeightProgress(), scale / 100f);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Saved presets change shape

Restoring a saved preset uses the slider values instead of the dimensions calculated by selectDevice(). Each slider has a minimum of 300, but a fitted preset can be narrower. For example, an iPhone X fitted into a 600px-high preview is about 277px wide. Selecting it uses that width, but reopening the saved default uses 300px and changes its shape. Keep the fitted dimensions when applying the restored scale.

@gahanad

gahanad commented Oct 18, 2026

Copy link
Copy Markdown
Contributor Author

Also isn't the line number area and editor area pinch-to-zoom at same time for better and smooth feel? as currently line number area adjusted itself after leaving zoom.

Also in some cases some accidental scrolls maybe using three finger/two finger etc does nothing but normally in acode those just scrolls so removing that will be a bit weird(if there is no valid reason)

I've added a guard so a three-finger touch no longer starts a pinch and keeps Acode's normal behaviour. For two fingers inside the editor the gesture is now claimed by pinch-to-zoom , that's the intended feature tradeoff , but if the browser starts native scrolling before the pinch is recognized, the code bails out and the scroll continues as before. Single-finger scrolling is untouched.

@gahanad

gahanad commented Oct 19, 2026

Copy link
Copy Markdown
Contributor Author

@greptile

Comment thread src/cm/pinchZoom.ts
Comment on lines +183 to +186
const fingerStillDown =
getTrackedTouch(event.touches, gesture.firstId) ||
getTrackedTouch(event.touches, gesture.secondId);
if (fingerStillDown) return;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 New pinch uses old distance

If a fresh pinch reuses finger identifiers after the previous gesture's end events were lost, fingerStillDown treats the new fingers as the old ones. It skips recovery and keeps the old starting distance.

For example, an abandoned 100px gesture followed by a new 200px → 240px pinch saves 29px instead of 14px from a 12px starting size. Use changedTouches to distinguish newly landed fingers from fingers that remain down before keeping the old gesture.

@greptile-apps

greptile-apps Bot commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

Want your agent to iterate on Greptile's feedback? Try greploops.

Comment thread src/cm/pinchZoom.ts
// The rest of the gesture is observed on document: a finger's
// original target (.cm-line) can be unmounted by the preview
// re-measure, and events for a detached node never bubble back.
addGestureListeners();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Moving these listeners to document doesn't cover the unmounted-line case: an event dispatched to a detached node only propagates through that node's own (detached) ancestors, so document is never on its path — capture or bubble. The comment above assumes otherwise.

Quick check: after line.remove(), a capture touchmove listener on document receives nothing, while one on line itself still fires.

So when the preview re-measure unmounts the .cm-line under both fingers:

  1. The zoomed preview stays inline and is never persisted.
  2. The document listeners stay attached.
  3. On the next touch in the editor, the recovery path in onTouchStart calls restorePreview(), so the size the user picked snaps back and is lost.

Suggest also attaching move/end/cancel to each tracked touch's target (first.target, second.target) at pinch start and removing them in endPinch/destroy — events for a detached element are still delivered to listeners on that element.

Comment thread src/cm/pinchZoom.ts
Comment on lines +356 to +358
target.removeEventListener("touchmove", onTouchMove, true);
target.removeEventListener("touchend", endPinch, true);
target.removeEventListener("touchcancel", endPinch, true);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: these three are never added to contentDOM anymore (they live on document and removeGestureListeners() above already cleans them up). Only the touchstart removal is needed here.

@bajrangCoder

Copy link
Copy Markdown
Member

Also there should be a small setting in settings.json file(no need on ui side) to toggle this behavior.(Overall it looks fine now except few reviews which is already posted)

@bajrangCoder bajrangCoder self-assigned this Oct 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community enhancement New feature or request

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

Request featured "Zoom"

4 participants