Skip to content

feat: enable turning off code ligatures#2476

Open
Kiwow wants to merge 2 commits intonpmx-dev:mainfrom
Kiwow:enable-disabling-code-ligatures
Open

feat: enable turning off code ligatures#2476
Kiwow wants to merge 2 commits intonpmx-dev:mainfrom
Kiwow:enable-disabling-code-ligatures

Conversation

@Kiwow
Copy link
Copy Markdown

@Kiwow Kiwow commented Apr 11, 2026

Closes #2423

Adds a new setting that controls whether ligatures are used in code. The setting sets a data attribute on the root, which is picked up by a selector in global styles.

I opted to have changes in the setting call the toggleCodeLigatures function rather than using v-model. This is needed because we need to run the side effect of updating the data attribute, which happens inside a watch is registered in useCodeLigatures. I still don't really like this, because the attribute update is dependent on useCodeLigatures being called, even though you can access and update the setting itself on settings. Other settings work like this as well though (e.g. the data attribute for keyboardShortcuts gets updated only if useKeyboardShortcuts is called), so for the time being, I've kept it this way. I'd be interested in revisiting this in the future, perhaps updating the useSettings composable to handle side effects on changes of individual settings. Please let me know if that makes sense to you.

I've provided translations for the new setting's label in English and Czech (my native language).

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 11, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
npmx.dev Ready Ready Preview, Comment Apr 11, 2026 3:06pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs.npmx.dev Ignored Ignored Preview Apr 11, 2026 3:06pm
npmx-lunaria Ignored Ignored Apr 11, 2026 3:06pm

Request Review

@github-actions
Copy link
Copy Markdown

Hello! Thank you for opening your first PR to npmx, @Kiwow! 🚀

Here’s what will happen next:

  1. Our GitHub bots will run to check your changes.
    If they spot any issues you will see some error messages on this PR.
    Don’t hesitate to ask any questions if you’re not sure what these mean!

  2. In a few minutes, you’ll be able to see a preview of your changes on Vercel

  3. One or more of our maintainers will take a look and may ask you to make changes.
    We try to be responsive, but don’t worry if this takes a few days.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 11, 2026

Lunaria Status Overview

🌕 This pull request will trigger status changes.

Learn more

By default, every PR changing files present in the Lunaria configuration's files property will be considered and trigger status changes accordingly.

You can change this by adding one of the keywords present in the ignoreKeywords property in your Lunaria configuration file in the PR's title (ignoring all files) or by including a tracker directive in the merged commit's description.

Tracked Files

File Note
i18n/locales/cs-CZ.json Localization changed, will be marked as complete.
i18n/locales/en.json Source changed, localizations will be marked as outdated.
Warnings reference
Icon Description
🔄️ The source for this localization has been updated since the creation of this pull request, make sure all changes in the source have been applied.

@Kiwow Kiwow changed the title feat: Enable turning off code ligatures feat: enable turning off code ligatures Apr 11, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 11, 2026

Codecov Report

❌ Patch coverage is 86.66667% with 2 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
app/pages/settings.vue 0.00% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@Kiwow Kiwow force-pushed the enable-disabling-code-ligatures branch from 84b65b6 to bd5155c Compare April 11, 2026 13:53
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 11, 2026

📝 Walkthrough

Walkthrough

Adds a settings toggle to enable/disable code ligatures. Introduces codeLigatures: boolean on AppSettings (default true), a useCodeLigatures() composable exposing the setting and toggleCodeLigatures(), and client-side syncing of document.documentElement.dataset.codeLigatures. Adds CSS to disable font ligatures when the dataset is 'false', updates prehydrate logic to apply the dataset before hydration, adds the UI toggle and translations, and includes unit tests for the composable.

Possibly related PRs

Suggested reviewers

  • danielroe
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The PR description clearly relates to the changeset, explaining the code ligatures feature, implementation approach, and design decisions with context.
Linked Issues check ✅ Passed The PR successfully implements the requested feature from issue #2423: a user-configurable setting to disable ligatures in code with CSS integration.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the code ligatures feature: CSS styling, settings composable, UI toggle, pre-hydration logic, i18n translations, schema updates, and tests.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
Copy Markdown
Contributor

@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.

🧹 Nitpick comments (1)
app/composables/useSettings.ts (1)

260-278: Wrap with createSharedComposable to align with codebase patterns and prevent future duplicate watchers.

This composable follows the same pattern as useKeyboardShortcuts (computed property + immediate watcher on a settings field). Currently only one production consumer exists in settings.vue, but wrapping with createSharedComposable ensures consistent behaviour if additional call sites are added, preventing duplicate side effects.

♻️ Suggested refactor
-export function useCodeLigatures() {
+export const useCodeLigatures = createSharedComposable(function useCodeLigatures() {
   const { settings } = useSettings()

   const codeLigatures = computed(() => settings.value.codeLigatures)

   if (import.meta.client) {
     // Sync the data attribute on root to the setting
     watch(
       codeLigatures,
       value => {
         if (value) {
           delete document.documentElement.dataset.codeLigatures
         } else {
           document.documentElement.dataset.codeLigatures = 'false'
         }
       },
       { immediate: true },
     )
   }

   function toggleCodeLigatures() {
     settings.value.codeLigatures = !settings.value.codeLigatures
   }

   return {
     codeLigatures,
     toggleCodeLigatures,
   }
-}
+})

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2b8ad8a1-e6d7-4a95-9bd4-f6f4bae29cec

📥 Commits

Reviewing files that changed from the base of the PR and between 0164064 and 84b65b6.

📒 Files selected for processing (7)
  • app/assets/main.css
  • app/composables/useSettings.ts
  • app/pages/settings.vue
  • app/utils/prehydrate.ts
  • i18n/locales/cs-CZ.json
  • i18n/locales/en.json
  • test/nuxt/composables/use-settings.spec.ts

@serhalp serhalp added the needs review This PR is waiting for a review from a maintainer label Apr 11, 2026
Copy link
Copy Markdown
Contributor

@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.

🧹 Nitpick comments (1)
app/composables/useSettings.ts (1)

260-288: Wrap useCodeLigatures with createSharedComposable for consistency with similar side effects.

This composable performs a global DOM mutation via watch, identical to useKeyboardShortcuts which already uses createSharedComposable. Whilst currently called only from settings.vue, wrapping it ensures singleton behaviour and aligns with the established pattern in the codebase.

♻️ Proposed refactor
-export function useCodeLigatures() {
+export const useCodeLigatures = createSharedComposable(function useCodeLigatures() {
   const { settings } = useSettings()

   const codeLigatures = computed(() => settings.value.codeLigatures)

   if (import.meta.client) {
     // Sync the data attribute on root to the setting
     watch(
       codeLigatures,
       value => {
         if (value) {
           delete document.documentElement.dataset.codeLigatures
         } else {
           document.documentElement.dataset.codeLigatures = 'false'
         }
       },
       { immediate: true },
     )
   }

   function toggleCodeLigatures() {
     settings.value.codeLigatures = !settings.value.codeLigatures
   }

   return {
     codeLigatures,
     toggleCodeLigatures,
   }
-}
+})

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 18833c17-f4e9-46b8-abec-daf82e5eb208

📥 Commits

Reviewing files that changed from the base of the PR and between 84b65b6 and bd5155c.

📒 Files selected for processing (8)
  • app/assets/main.css
  • app/composables/useSettings.ts
  • app/pages/settings.vue
  • app/utils/prehydrate.ts
  • i18n/locales/cs-CZ.json
  • i18n/locales/en.json
  • i18n/schema.json
  • test/nuxt/composables/use-settings.spec.ts
✅ Files skipped from review due to trivial changes (3)
  • app/assets/main.css
  • test/nuxt/composables/use-settings.spec.ts
  • i18n/locales/cs-CZ.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • app/pages/settings.vue
  • app/utils/prehydrate.ts
  • i18n/locales/en.json

@Kiwow
Copy link
Copy Markdown
Author

Kiwow commented Apr 11, 2026

I don't totally understand createSharedComposable, but after reading a bit of the effectScope RFC, I think it's a good thing to use here?

I'm happy to add it if anyone reviewing this thinks it makes sense to use it.

EDIT: After thinking about it a bit more, I think it makes sense to use it here, so I've done so

Copy link
Copy Markdown
Contributor

@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.

🧹 Nitpick comments (1)
app/composables/useSettings.ts (1)

265-277: Consider a tiny helper to deduplicate root dataset boolean syncing.

This watch block duplicates the same pattern used in useKeyboardShortcuts (set attribute to 'false' when disabled, remove when enabled). Extracting that pattern into a small helper would reduce repetition and keep future flag additions simpler.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d7bdbaf0-8237-422e-9506-a313f501c8c8

📥 Commits

Reviewing files that changed from the base of the PR and between bd5155c and 81179de.

📒 Files selected for processing (1)
  • app/composables/useSettings.ts

@ghostdevv ghostdevv requested a review from serhalp April 12, 2026 01:53
}
}

export const useCodeLigatures = createSharedComposable(function useCodeLigatures() {
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.

Suggested change
export const useCodeLigatures = createSharedComposable(function useCodeLigatures() {
export const useCodeLigatures = createSharedComposable(() => {

Copy link
Copy Markdown
Author

@Kiwow Kiwow Apr 12, 2026

Choose a reason for hiding this comment

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

I saw this in the useKeyboardShortcuts composable and it made sense to me as a way to get nicer stack traces in logs. I think it's nice to have a named function for that reason.

To be fair, in prod builds, it won't make a difference, so I'm up for either solution. Your version is definitely more readable.

To compare, here's the outputs of `console.trace` (running in dev) when called at the start of the composable and the start of the watcher function, respectively:

Named function expression:

Two stack traces. Both contain 'useCodeLigatures' as part of the trace, as well as Vue-specific functions

Anonymous arrow function:

Two stack traces. Outside of Vue-specific functions, the traces only contain references to anonymous functions

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

Labels

needs review This PR is waiting for a review from a maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

an option to disable ligatures in code

3 participants