[Bug]: Manifest visual editor loses tab/scroll state when the XML is edited in the text editor

Đã đóng
#192 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 11 ngày

@chiaramooney đang làm issue này rồi.

Từ ngày 21/8/2026.

  • #194 của @chiaramooney — đang mở

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
52/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Ít trao đổi
Công nghệ
typescript
Lĩnh vực
frontend

Hướng nghiên cứu

Bắt đầu với src/manifest-editor/manifest-editor-provider.ts, webview-script.ts, webview-script-applications.ts, webview-content.ts và webview-styles.ts. Theo dõi các cập nhật tài liệu bên ngoài qua phần xử lý lỗi phân tích cú pháp và các trình render danh sách, sau đó xác định cách bảo toàn trạng thái webview hiện có và các offset cuộn. Hoàn thành khi các chỉnh sửa bên ngoài, bao gồm cả XML tạm thời không hợp lệ, vẫn giữ nguyên các tab, các trường đã mở rộng, tiêu điểm và vị trí cuộn mà không tạo ra các nút tab không nhất quán.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

bug
Describe the bug

With an AppxManifest.xml open in both the visual manifest editor and the XML text editor, editing and saving the XML causes the visual editor to lose its UI state — the selected top-level tab, the selected per-application sub-tab (Info / Extensions / Visual Assets), any optional fields the user had expanded, and the scroll position.

Confusingly, it only happens for some edits. Changing an attribute value (e.g. Properties/DisplayName, Identity/Version) preserves state. Adding or removing a <Capability> element resets the editor back to the Identity tab / Info sub-tab.

There are two distinct root causes.


Root cause 1 — the webview document is torn down and rebuilt on transiently-invalid XML

vscode.workspace.onDidChangeTextDocument fires on every keystroke, not just on save (src/manifest-editor/manifest-editor-provider.ts:169-182).

If the document fails to parse at any intermediate moment, tryParseOrShowError replaces the whole webview document with the parse-error page (manifest-editor-provider.ts:74-86). Once the XML parses again, showEditorView() assigns a brand-new webviewPanel.webview.html (manifest-editor-provider.ts:89-93).

That is a full script-context teardown, so every piece of state held in webview JS memory is destroyed:

State Where it lives Survives valid→valid edit Survives valid→invalid→valid edit
Top-level tab DOM classes ✅ ❌ resets to Identity
App sub-tab (Info / Extensions / Visual Assets) activeAppSubTabs — src/manifest-editor/webview-script.ts:24 ✅ ❌ resets to Info
User-opened optional fields userOpenedOptionalFields — webview-script.ts:26 ✅ ❌ collapse again
Scroll position DOM ❌ (see root cause 2) ❌

This explains the asymmetry. Verified against @xmldom/xmldom with the same parseManifestXml error handling the extension uses (src/manifest-schema/xml-parser.ts:33):

adding a <Capability> element          editing an attribute value
-----------------------------          -------------------------
INVALID   "<"                            valid   ""
INVALID   "<C"                           valid   "1"
INVALID   "<Cap"                         valid   "1."
INVALID   "<Capability"                  valid   "1.0"
INVALID   "<Capability "
INVALID   "<Capability Name="
INVALID   "<Capability Name=\"x\""
  valid   "<Capability Name=\"x\" />"

Typing an element passes through many invalid states, each one flipping the webview to the error page and back. Editing a value in place never breaks the XML, so nothing is torn down.

Note that the state is also lost on a genuine VS Code reload, because the webview never persists anything via vscode.setState() (no setState/getState calls anywhere in src/manifest-editor/).

Root cause 2 — scroll position resets on every external edit

.tab-content is the scroll container (overflow-y: auto, src/manifest-editor/webview-styles.ts:76), and renderApplications starts with container.innerHTML = '' (src/manifest-editor/webview-script-applications.ts:71-73). Clearing the list collapses the scroll height, the browser clamps scrollTop to 0, and the subsequent re-render leaves it there. The same pattern applies to the dependencies and resources renderers.

Additionally, external edits call updateWebview(true), and populateForm sets focused = null when forceAll is set (webview-script.ts:283), so focus restore is skipped entirely for these updates.


Two smaller issues found while investigating
  • The parse-error page listens for a retryParse message (src/manifest-editor/webview-content.ts:60), but nothing in the extension ever posts it — dead code. The provider calls showEditorView() directly instead.
  • When a tab is hidden based on package type, only the .tab-content has active removed; the corresponding .tab-btn keeps its active class (webview-script.ts:393-395, :403-405, :413-415 vs. the fallback at :417-422). Two tab buttons can end up looking selected at the same time.
To Reproduce
  1. Open an AppxManifest.xml in the visual manifest editor.
  2. Go to the Applications tab and select the Visual Assets sub-tab.
  3. Open the same file in the XML text editor (View XML / Open With… > Text Editor).
  4. Type a new <Capability Name="internetClient" /> line inside <Capabilities> (or delete an existing one character by character), then save.
  5. Ctrl+Tab back to the visual editor.

Observed: the editor is back on the Identity tab; the Applications sub-tab has reverted to Info; expanded optional fields are collapsed; scroll is at the top.

For contrast, repeat with an edit that keeps the XML valid at every keystroke — e.g. changing Identity/@Version from 1.0.0.0 to 1.0.0.1. The tab and sub-tab selection are preserved (though scroll still resets).

Expected behavior

Switching back to the visual editor after an external XML edit should leave the user exactly where they were: same top-level tab, same per-application sub-tab, same expanded optional fields, same scroll position. Transiently-invalid XML while the user is mid-keystroke in the text editor should not reset the visual editor's UI state.

Suggested fix
  1. Stop reassigning webview.html for parse failures — render the parse error as an overlay inside the existing document (and/or debounce it) so transient invalid states never tear down the script context.
  2. Persist UI state (activeAppSubTabs, active top-level tab, userOpenedOptionalFields, scroll offsets) via vscode.setState() / getState() so it also survives a genuine webview reload.
  3. Save and restore scrollTop around the list re-renders in renderApplications / renderResources / the dependency renderers.
  4. While in there: remove the dead retryParse handler and keep .tab-btn.active in sync with .tab-content.active when tabs are hidden by package type.
Screenshots

N/A

OS Version and details

Windows 11

Ngôn ngữ chính
TypeScript
Star
15
Fork
4
Merge trung bình
10 ngày 10 giờ
Pull request đã merge (30 ngày)
9

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của microsoft/WinAppVSCE

Tất cả issue của microsoft/WinAppVSCE

Issue tương tự

Thêm issue về TypeScript

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.