Skip to content

[issues/280] Hide Bookmarks feature behind setting (beta)#367

Merged
couimet merged 9 commits intomainfrom
issues/280
Feb 18, 2026
Merged

[issues/280] Hide Bookmarks feature behind setting (beta)#367
couimet merged 9 commits intomainfrom
issues/280

Conversation

@couimet
Copy link
Owner

@couimet couimet commented Feb 18, 2026

Summary

Hides the Bookmarks feature behind an opt-in features.bookmarks.enabled setting (default: false) so it ships as dormant code in 1.1.0. A two-layer gate — declarative when clauses in package.json for UI visibility, plus BookmarkService.isVisible() for the R-M status bar menu — ensures bookmarks are completely invisible to users unless they manually enable the setting. All bookmark code remains in git and initializes normally to minimize SCM noise.

Changes

  • New setting: rangelink.features.bookmarks.enabled (boolean, default false) with constants in settingKeys.ts and settingDefaults.ts
  • package.json when clauses: Bookmark keybindings (R-B-S, R-B-L), editor context menu (Save Selection as Bookmark), and Command Palette entries gated by config.rangelink.features.bookmarks.enabled
  • BookmarkService.isVisible(): New visible flag on BookmarkService constructor, read from the setting at activation. Status bar menu checks isVisible() to conditionally render the bookmark section in R-M
  • README hidden: 5 bookmark-related sections wrapped in <!-- --> HTML comments (Bookmarks section, command table rows, context menu row, Smart Padding row, R-M menu bullet)
  • CHANGELOG hidden: 3 bookmark references in [Unreleased] wrapped in <!-- --> HTML comments
  • TODO: Unhide Bookmarks feature (remove beta gate) #366 markers: All gated locations tagged for easy cleanup when bookmarks graduates from beta in 2.0.0
  • Follow-up issue: Created Unhide Bookmarks feature (remove beta gate) #366 (child of Prepare for extension's 2.0.0 release #283) to track re-enabling bookmarks for 2.0.0

Test Plan

  • All existing tests pass (1454 tests, 74 suites)
  • New tests: features.bookmarks.enabled contract test in packageJsonContracts.test.ts, bookmark when clause tests for keybindings/commandPalette/context menus
  • BookmarkService mock helper updated with isVisible() — all StatusBar tests pass

Related

Summary by CodeRabbit

  • New Features

    • Added a new configuration setting to enable the Bookmarks feature (beta). Bookmark functionality is now disabled by default and can be activated via settings.
  • Documentation

    • Updated extension documentation to reflect bookmark feature availability and configuration options.

Foundation for hiding Bookmarks behind an opt-in beta flag.
The setting defaults to `false` so bookmarks are invisible to
users in 1.1.0 — subsequent commits will wire the `when` clauses
and runtime guards that read this value.
…ses (#280)

When `features.bookmarks.enabled` is false (the default), bookmark
commands vanish from the Command Palette, keybindings are inert, and
the editor context menu "Save Selection as Bookmark" entry is hidden.

Uses the standard VSCode `config.rangelink.features.bookmarks.enabled`
when-clause pattern so the UI layer handles visibility declaratively —
no runtime code needed for these touchpoints.
…#280)

BookmarkService now carries a `visible` flag (from the
`features.bookmarks.enabled` setting). The status bar checks
`isVisible()` to decide whether to render bookmark items in R-M.

All bookmark code still initializes — commands are always registered
(package.json `when` clauses handle Command Palette / keybinding
visibility). This keeps SCM noise low and avoids optional params.

TODO: #366 markers added at all gate points for easy cleanup
when bookmarks graduates from beta in 2.0.0.
5 locations wrapped in `<!-- -->` so bookmark documentation is
invisible on GitHub/npmjs but preserved in git for #366:

- Bookmarks bullet in the R-M menu description
- Full Bookmarks section (Save/List instructions)
- Two command table rows (R-B-S, R-B-L)
- Editor context menu row (Save Selection as Bookmark)
- Smart Padding pasteBookmark setting row
3 locations wrapped in `<!-- -->` in the [Unreleased] section:

- "List Bookmarks / Manage Bookmarks" menu item bullet
- "Save Selection as Bookmark" context menu entry
- Full "Bookmarks System" feature entry (R-B-S, R-B-L)

All tagged with TODO: #366 for easy cleanup in 2.0.0.
@coderabbitai
Copy link

coderabbitai bot commented Feb 18, 2026

No actionable comments were generated in the recent review. 🎉


Walkthrough

A bookmarks feature flag is introduced with default value false, gating all bookmark UI elements, commands, and menus behind the configuration rangelink.features.bookmarks.enabled. A visibility check method is added to BookmarkService, and the status bar conditionally renders bookmarks based on this flag. Documentation is updated to reflect beta status.

Changes

Cohort / File(s) Summary
Feature Configuration
package.json, src/constants/settingKeys.ts, src/constants/settingDefaults.ts
New configuration property rangelink.features.bookmarks.enabled (default: false) added with associated setting key and default constant; bookmark commands, keybindings, and menu entries gated behind this feature flag.
Feature Visibility Implementation
src/bookmarks/BookmarkService.ts, src/statusBar/RangeLinkStatusBar.ts
BookmarkService gains isVisible() method that reads the feature flag; status bar conditionally includes bookmarks section based on visibility state.
Documentation
CHANGELOG.md, README.md
Changelog and README updated to document bookmarks as hidden beta feature; bookmark-related sections wrapped in TODO/unreleased blocks; new "Smart Padding settings documented" entry added.
Test Updates
src/__tests__/constants/packageJsonContracts.test.ts, src/__tests__/helpers/createMockBookmarkService.ts
Test mock expanded with isVisible() method; package.json contract tests updated to validate feature flag configuration, gated command palette entries, and menu conditions; configuration property count incremented.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • Linked issue #280: This PR fully implements the "Hide Bookmarks feature behind setting (beta)" requirement by introducing the new setting, gating all bookmark UI, adding visibility checks, and updating documentation.

Possibly related PRs

Poem

📚✨ A flag is born, the bookmarks hide,
Behind a setting, set to false with pride,
When users dare to flip the switch so bright,
Beta features bloom and shine with light! 🐰

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title directly and clearly summarizes the main change: hiding the Bookmarks feature behind a beta setting flag.
Linked Issues check ✅ Passed All coding requirements from issue #280 are implemented: setting added with default false, bookmarks hidden in package.json when clauses, BookmarkService.isVisible() runtime check, and constants defined.
Out of Scope Changes check ✅ Passed All changes are within scope: they consistently implement the feature flag gate for bookmarks across package.json, tests, BookmarkService, status bar, and documentation.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch issues/280

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
packages/rangelink-vscode-extension/src/extension.ts (1)

138-138: Debug log doesn't distinguish default vs. user-configured path.

-logger.debug({ fn: 'activate', bookmarksEnabled }, 'Bookmarks feature flag read');
+logger.debug(
+  { fn: 'activate', bookmarksEnabled, isDefault: bookmarksEnabled === DEFAULT_FEATURES_BOOKMARKS_ENABLED },
+  'Bookmarks feature flag read',
+);

As per coding guidelines, "Log at DEBUG level when using default vs provided values to indicate which path was taken."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/rangelink-vscode-extension/src/extension.ts` at line 138, The debug
log at logger.debug({ fn: 'activate', bookmarksEnabled }, 'Bookmarks feature
flag read') doesn't indicate whether a default path was used or a user-specified
one; update the log to include the resolved bookmarks path and a flag (e.g.,
bookmarksPath and bookmarksPathIsDefault) so the activate flow shows which
branch was taken. Locate the code that resolves the bookmarks path (in the
activate function) and augment the logger.debug call to include those symbols so
the log clearly distinguishes default vs user-configured path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/rangelink-vscode-extension/CHANGELOG.md`:
- Line 63: The "Editor Content" line currently has multiple sub-items condensed
onto one line; split that single run-on line into separate markdown list entries
so each command is its own bullet like the other blocks (e.g., break the text
into separate indented lines for "RangeLink: Copy Range Link", "RangeLink: Copy
Range Link (Absolute)", "RangeLink: Copy Portable Link", "RangeLink: Copy
Portable Link (Absolute)", and "RangeLink: Paste Selected Text"), matching the
indentation/style used on lines 67–71 and preserving the surrounding
TODO/context.

In `@packages/rangelink-vscode-extension/README.md`:
- Around line 271-278: Remove the blank lines immediately before and after the
HTML comment blocks that hide unreleased rows in the README table so the
Markdown table remains contiguous; specifically, edit the commands table block
containing the comment around the "Save Selection as Bookmark" / "List
Bookmarks" rows (the <!-- TODO: `#366` ... --> block) and the similar comment
blocks near the "Editor Content" and "Smart Padding" tables so there are no
empty lines adjacent to the HTML comments, preserving the header/separator + row
sequence and ensuring subsequent rows like "Go to Link <sup>Unreleased</sup>"
render as table rows.

In `@packages/rangelink-vscode-extension/src/extension.ts`:
- Around line 133-138: The bookmarksEnabled flag is captured once at activation
and never updated, causing BookmarkService.isVisible() to stay stale; update the
implementation so visibility is read dynamically: change
BookmarkService.isVisible() to query
configReader.getBoolean(SETTING_FEATURES_BOOKMARKS_ENABLED,
DEFAULT_FEATURES_BOOKMARKS_ENABLED) each call instead of relying on the
activation-time bookmarksEnabled value, or alternatively add an
onDidChangeConfiguration listener in extension.ts that updates the
BookmarkService visibility state (and prompts reload if needed); reference the
bookmarksEnabled variable in extension.ts and the BookmarkService.isVisible()
method to locate where to remove the frozen flag and perform the dynamic read or
the config change wiring.

---

Nitpick comments:
In `@packages/rangelink-vscode-extension/src/extension.ts`:
- Line 138: The debug log at logger.debug({ fn: 'activate', bookmarksEnabled },
'Bookmarks feature flag read') doesn't indicate whether a default path was used
or a user-specified one; update the log to include the resolved bookmarks path
and a flag (e.g., bookmarksPath and bookmarksPathIsDefault) so the activate flow
shows which branch was taken. Locate the code that resolves the bookmarks path
(in the activate function) and augment the logger.debug call to include those
symbols so the log clearly distinguishes default vs user-configured path.

Comment on lines 133 to 138
// TODO: #366 remove feature flag when bookmarks graduates from beta
const bookmarksEnabled = configReader.getBoolean(
SETTING_FEATURES_BOOKMARKS_ENABLED,
DEFAULT_FEATURES_BOOKMARKS_ENABLED,
);
logger.debug({ fn: 'activate', bookmarksEnabled }, 'Bookmarks feature flag read');
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

bookmarksEnabled is captured once at activation; no config-change listener is registered.

The when clauses in package.json are re-evaluated by VS Code dynamically — toggling rangelink.features.bookmarks.enabled in settings will immediately show/hide bookmark commands in the palette, keybindings, and context menu. However, bookmarkService.isVisible() always returns the activation-time value, so the status-bar bookmark section stays out of sync until a window reload. The disable path is worse: commands disappear from all UI surfaces, but the status bar still renders bookmark items.

Preferred fix — make isVisible() read from configReader dynamically inside BookmarkService instead of storing a frozen flag:

🔧 Option A — dynamic read in BookmarkService.isVisible() (no listener needed)

In BookmarkService.ts:

 constructor(
   private readonly bookmarksStore: BookmarksStore,
   private readonly ideAdapter: VscodeAdapter,
   private readonly configReader: ConfigReader,
   private readonly destinationManager: PasteDestinationManager,
   private readonly logger: Logger,
-  private readonly visible: boolean = true,
 ) { ... }

 isVisible(): boolean {
-  return this.visible;
+  return this.configReader.getBoolean(
+    SETTING_FEATURES_BOOKMARKS_ENABLED,
+    DEFAULT_FEATURES_BOOKMARKS_ENABLED,
+  );
 }

In extension.ts:

-const bookmarksEnabled = configReader.getBoolean(
-  SETTING_FEATURES_BOOKMARKS_ENABLED,
-  DEFAULT_FEATURES_BOOKMARKS_ENABLED,
-);
-logger.debug({ fn: 'activate', bookmarksEnabled }, 'Bookmarks feature flag read');
-
 const bookmarksStore = new BookmarksStore(context.globalState, logger);
 const bookmarkService = new BookmarkService(
   bookmarksStore,
   ideAdapter,
   configReader,
   destinationManager,
   logger,
-  bookmarksEnabled,
 );
🔧 Option B — onDidChangeConfiguration listener with reload prompt (minimal invasiveness)
+context.subscriptions.push(
+  vscode.workspace.onDidChangeConfiguration((e) => {
+    if (e.affectsConfiguration(`rangelink.${SETTING_FEATURES_BOOKMARKS_ENABLED}`)) {
+      // TODO: `#366` remove when bookmarks graduates from beta
+      void ideAdapter.showInformationMessage(
+        'Reload the window to apply Bookmarks visibility changes.',
+        'Reload Window',
+      ).then((action) => {
+        if (action === 'Reload Window') {
+          void vscode.commands.executeCommand('workbench.action.reloadWindow');
+        }
+      });
+    }
+  }),
+);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/rangelink-vscode-extension/src/extension.ts` around lines 133 - 138,
The bookmarksEnabled flag is captured once at activation and never updated,
causing BookmarkService.isVisible() to stay stale; update the implementation so
visibility is read dynamically: change BookmarkService.isVisible() to query
configReader.getBoolean(SETTING_FEATURES_BOOKMARKS_ENABLED,
DEFAULT_FEATURES_BOOKMARKS_ENABLED) each call instead of relying on the
activation-time bookmarksEnabled value, or alternatively add an
onDidChangeConfiguration listener in extension.ts that updates the
BookmarkService visibility state (and prompts reload if needed); reference the
bookmarksEnabled variable in extension.ts and the BookmarkService.isVisible()
method to locate where to remove the frozen flag and perform the dynamic read or
the config change wiring.

Addresses CodeRabbit review on PR #367:

- Split CHANGELOG line 63 back into individual bullets (was a
  collapsed run-on line that broke markdown rendering)
- Remove blank lines around HTML comment blocks in README tables
  (blank lines terminate GFM tables, causing rows to render as
  plain text)
- Make BookmarkService.isVisible() read from configReader dynamically
  instead of storing a frozen activation-time flag — the R-M menu
  now stays in sync when users toggle the setting without reload

Ignored Feedback:
- Debug log isDefault flag: ConfigReader.getWithDefault() already
  logs "using default" vs "using configured value" at DEBUG level;
  adding isDefault to the caller would duplicate this information

Ref: #367 (review)
HTML comments inside GFM tables terminate the table — rows after
the comment render as plain text on GitHub. Moved all hidden
bookmark rows out of their tables into standalone `<!-- -->` blocks
below each section, with instructions for where to re-insert them.

Also removes `prettier-ignore-start/end` directives that were
working around the same issue less cleanly.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/rangelink-vscode-extension/CHANGELOG.md`:
- Around line 84-94: Update the TODO comment that currently reads "TODO: `#366`
unhide when bookmarks graduates from beta" to use correct subject-verb agreement
by changing "graduates" to "graduate" (i.e., "TODO: `#366` unhide when bookmarks
graduate from beta"); locate the phrase in the existing commented block
containing the bookmarks TODO and replace only that word to preserve the rest of
the comment.

@couimet couimet merged commit 76b6a22 into main Feb 18, 2026
2 checks passed
@couimet couimet deleted the issues/280 branch February 18, 2026 13:48
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.

Hide Bookmarks feature behind setting (beta)

1 participant