Skip to content

Function list: fix Java parsing and add C# support - #115

Merged
hybridmachine merged 2 commits into
macos-portfrom
feature/function-list-java-csharp
Jun 11, 2026
Merged

Function list: fix Java parsing and add C# support#115
hybridmachine merged 2 commits into
macos-portfrom
feature/function-list-java-csharp

Conversation

@hybridmachine

Copy link
Copy Markdown
Owner

Summary

The function browser missed most Java methods, and C# wasn't a supported language at all. This fixes Java parsing and adds full C# support (highlighting + function list).

Java was broken

The Java regex required ) immediately followed by {, so on a representative file it found only 2 of 7 methods. It missed:

  • throws clausesvoid readFile() throws IOException {
  • Same-line annotations@Override public String toString() {
  • Allman braces — signature on one line, { on the next (the Java path had no pending-signature handling; C++ did)

It also listed control statements (if/while/try) as methods.

C# was absent

No LANG_CSHARP, no .cs detection, no language-table entry — so C# files got no syntax highlighting and an empty function list.

Changes

  • function_list_parser.mm — rework the Java path into a shared Java/C# branch: annotations, throws, Allman pending-signatures, C# expression-bodied members (=>), : base(...) constructors, where constraints, and class|struct|interface|enum|record containers. Control keywords filtered via a separate set so lock/using stay valid C++ names. Regexes match modifiers/types token-wise behind cheap string prefilters.
  • language_defs.{h,mm} — add LANG_CSHARP = 36 (appended at the end of the table, since sessions persist languageIndex as a raw int), C# keyword/type lists on the cpp lexer (as upstream Notepad++ does), .cs/.csx detection, C-style indentation.
  • npp_constants.h — move IDM_LANG_BASE 44000 → 51000. This fixes a latent bug: 44000+ is upstream's plugin-visible view-command range, and the language range check runs first in MainWndProc, so 44035 (IDM_VIEW_SYNSCROLLV, sent by ComparePlus) was misrouted to "set language to x86 Assembly". The move also makes room for the 37th language.

Verification

  • Parser harness (real parser compiled standalone): comprehensive Java/C# samples pass; C++/Python output is byte-identical to the old parser on regression inputs.
  • Performance: the first regex draft backtracked badly (195s on a 127k-line C# file). Restructured to token-wise matching + prefilters → ~5s on 115k+ line Java/C# files (the old parser took 57s on the same Java input). Typical files parse in milliseconds.
  • Live app: C# appears in the Language menu; Sample.cs renders the full C# tree (classes, ctors incl. : base(...), async methods, expression-bodied members — properties correctly excluded); Java.java renders all expected rows including every previously-missing pattern.

🤖 Generated with Claude Code

The function browser missed most Java methods — on a representative file
it found only 2 of 7. The Java regex required ')' immediately followed by
'{', so it failed on `throws` clauses, same-line annotations
(`@Override public ... {`), and Allman-style braces (signature on one line,
'{' on the next, which the Java path never handled). It also listed control
statements like `if`/`while`/`try` as methods.

C# was not a language in the port at all: no LANG_CSHARP, no .cs detection,
no table entry — hence no highlighting and no function list.

Changes:
- function_list_parser.mm: rework the Java path into a shared Java/C# branch
  handling annotations, throws clauses, Allman pending-signatures, C#
  expression-bodied members (=>), ": base(...)" constructors, "where"
  constraints, and class|struct|interface|enum|record containers. Filter
  control keywords (separate set so "lock"/"using" stay valid C++ names).
  Regexes match modifiers/types token-wise with cheap string prefilters —
  the naive form took minutes on large files; this is ~5s on 115k+ lines.
- language_defs.{h,mm}: add LANG_CSHARP=36 (appended at end of table since
  sessions persist languageIndex as a raw int), C# keyword/type lists on the
  cpp lexer, .cs/.csx detection, and C-style indentation.
- npp_constants.h: move IDM_LANG_BASE 44000 -> 51000. 44000+ is upstream's
  plugin-visible view-command range, and the language range check runs first
  in MainWndProc, so 44035 (IDM_VIEW_SYNSCROLLV, sent by ComparePlus) was
  being misrouted to "set language to x86 Assembly". The move also makes room
  for the 37th language.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 11, 2026 04:19

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR improves the macOS function list browser by fixing Java method detection and adding first-class C# support (syntax highlighting via the existing cpp lexer plus function/container extraction). It also moves the language-menu command-ID range to avoid collisions with upstream Notepad++ command IDs that plugins may send by value.

Changes:

  • Move IDM_LANG_BASE to a safe range to prevent plugin-sent upstream view commands (e.g., sync scroll) from being misrouted as “set language”.
  • Add LANG_CSHARP, C# language table entry, .cs/.csx detection, and mark C# as C-style indentation.
  • Rework the function list parser to share a Java/C# parsing path with annotation/throws handling, Allman-style pending signatures, and C#-specific syntax forms.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
macos/platform/npp_constants.h Moves language command-ID base away from upstream plugin command ranges; adds explanatory comments.
macos/platform/language_defs.mm Adds C# language definition, extension detection, and C-style indentation classification.
macos/platform/language_defs.h Introduces LANG_CSHARP language index.
macos/platform/function_list_parser.mm Adds Java/C# shared parsing branch and new regexes/filters for more accurate container + function extraction.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread macos/platform/npp_constants.h Outdated
Comment on lines +52 to +55
// Base for language menu items. Must stay clear of upstream menuCmdID.h values
// (which run up to 50000): plugins send those by value, and the language range
// check in MainWndProc runs first, so a base of 44000 shadowed upstream view
// commands such as IDM_VIEW_SYNSCROLLV/H (44035/44036, sent by ComparePlus).

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Confirmed — the vendored menuCmdID.h tops out at IDM_EDIT_FUNCCALLTIP_NEXT = 50011 (autocomplete block at 50000+). Comment corrected in 744d028; the 51000 base itself is unaffected since nothing upstream sits in 51000–51100 (verified by resolving every #define in the header).

Comment thread macos/platform/function_list_parser.mm Outdated
// bare "name(...) {" is rejected so calls/control statements don't match.
// Modifiers and type are matched token-wise (no bare \s alternation):
// whitespace-splitting ambiguity in std::regex costs minutes on large files.
static const std::regex javaCsClassRe(R"(\b(class|struct|interface|enum|record)\s+([A-Za-z_]\w*))");

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Good catch — confirmed with a failing test: record struct Coordinate(...) produced a container literally named "struct". Fixed in 744d028 by matching record class/record struct as a unit in javaCsClassRe (longest alternative first, name capture unchanged). Harness now covers record struct and readonly record class with methods grouped under the right containers.

…curacy

- javaCsClassRe now matches "record class X" / "record struct X" (C# 10) as a
  unit; previously the second keyword was captured as the container name, so
  "record struct Point(...)" produced a container named "struct".
- Correct the IDM_LANG_BASE comment: upstream menuCmdID.h IDs top out at
  IDM_EDIT_FUNCCALLTIP_NEXT = 50011 (autocomplete block at 50000+), not 50000.
  The 51000 base itself is unaffected — nothing upstream sits in 51000-51100.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@hybridmachine
hybridmachine merged commit d084118 into macos-port Jun 11, 2026
27 of 34 checks passed
hybridmachine added a commit that referenced this pull request Jun 13, 2026
…alEffectView dealloc crash (#116)

* Render GFM tables in the markdown viewer plugin

The hand-rolled markdown parser had no table support, so pipe-delimited
rows fell through to paragraph accumulation and rendered as one wrapped
block of text. Add GFM table detection (header + delimiter row), HTML
emission with column alignment from `:---:` style delimiters, inline
markdown inside cells, padding/truncation of mismatched rows, escaped
`\|` handling, and matching light/dark CSS for <table>/<th>/<td>.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Address PR #114 review: require header column count to match delimiter

Per GFM spec the header row must match the delimiter row in cell count,
otherwise the block is not a table. Previously a mismatch was padded /
truncated like body rows, which could swallow plain text that happens to
contain pipes when followed by a `---` line. Tighten the gate to
`headerCells.size() == aligns.size()` and drop the now-redundant header
normalization inside emitTable; body rows still pad/truncate as before.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Fix SC_AUTOMATICFOLD_CLICK value and guard shim command macros

Follow-ups from the ComparePlus navigation verification pass:
- SC_AUTOMATICFOLD_CLICK was 0x0004 (the value of SC_AUTOMATICFOLD_CHANGE);
  Scintilla defines it as 0x0002
- Guard GET_WM_COMMAND_* in windowsx.h against redefinition with winuser.h
- Silence -Wdeprecated-this-capture (Scintilla) and pragma-message noise
  (ComparePlus) in the plugin builds

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Bump version to 1.0.8

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Function list: fix Java parsing and add C# support

The function browser missed most Java methods — on a representative file
it found only 2 of 7. The Java regex required ')' immediately followed by
'{', so it failed on `throws` clauses, same-line annotations
(`@Override public ... {`), and Allman-style braces (signature on one line,
'{' on the next, which the Java path never handled). It also listed control
statements like `if`/`while`/`try` as methods.

C# was not a language in the port at all: no LANG_CSHARP, no .cs detection,
no table entry — hence no highlighting and no function list.

Changes:
- function_list_parser.mm: rework the Java path into a shared Java/C# branch
  handling annotations, throws clauses, Allman pending-signatures, C#
  expression-bodied members (=>), ": base(...)" constructors, "where"
  constraints, and class|struct|interface|enum|record containers. Filter
  control keywords (separate set so "lock"/"using" stay valid C++ names).
  Regexes match modifiers/types token-wise with cheap string prefilters —
  the naive form took minutes on large files; this is ~5s on 115k+ lines.
- language_defs.{h,mm}: add LANG_CSHARP=36 (appended at end of table since
  sessions persist languageIndex as a raw int), C# keyword/type lists on the
  cpp lexer, .cs/.csx detection, and C-style indentation.
- npp_constants.h: move IDM_LANG_BASE 44000 -> 51000. 44000+ is upstream's
  plugin-visible view-command range, and the language range check runs first
  in MainWndProc, so 44035 (IDM_VIEW_SYNSCROLLV, sent by ComparePlus) was
  being misrouted to "set language to x86 Assembly". The move also makes room
  for the 37th language.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Address PR #115 review: record struct/class containers, ID comment accuracy

- javaCsClassRe now matches "record class X" / "record struct X" (C# 10) as a
  unit; previously the second keyword was captured as the container name, so
  "record struct Point(...)" produced a container named "struct".
- Correct the IDM_LANG_BASE comment: upstream menuCmdID.h IDs top out at
  IDM_EDIT_FUNCCALLTIP_NEXT = 50011 (autocomplete block at 50000+), not 50000.
  The 51000 base itself is unaffected — nothing upstream sits in 51000-51100.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Bump version to 1.0.9; add C# document type to Info.plist

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: remove stale notification observer object filters causing NSVisualEffectView dealloc crash

- Changed three NSNotificationCenter registration object: parameters from
  dangling-capable pointers to nil in ScintillaView.mm (initWithFrame:)
  - NSWindowWillMoveNotification: self.window -> nil
  - NSSystemColorsDidChangeNotification: self.window -> nil
  - NSViewBoundsDidChangeNotification: scrollView.contentView -> nil
  All three handlers ignore the notification object, so no behavioral change.
  This eliminates the stale pointer in the notification center's internal
  data structures that caused a SIGBUS crash when AppKit's internal
  NSVisualEffectView was deallocated during autorelease pool drain.

- Added dealloc to NppAppDelegate to remove observer from
  NSDistributedNotificationCenter (AppleInterfaceThemeChangedNotification).

- Added missing ScintillaBridge_destroyView call for scintillaView2 in
  applicationWillTerminate: to balance __bridge_retained from createView.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: require at least 3 dashes per GFM table delimiter column

The GFM spec requires 3+ dashes in delimiter rows (e.g. ---, :---:, ---:).
Previously a single dash per column would pass validation, causing
false-positive table parsing for inputs that should not be tables.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Brian Tabone <brian.tabone@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants