Skip to content

Conversation

@bezustally
Copy link

Overview

Adds support for @match directive in usercss files.

Closes #2002

What's Added

  • @match directive support for URL pattern matching
  • Enhanced meta parser to handle @match directives
  • Updated style matcher and usercss compiler for @match compatibility
  • UI improvements to display @match patterns in style management and installation

Usage

@match https://example.com/*
@match https://*.github.com/*

body {
  background: red;
}

Styles with @match directives will now only apply to the specified domains.

UI Changes

  • Enhanced installation UI with favicon display for @match domains
image - Added display of `@match` patterns in the style management interface image

Files Changed

  • src/js/meta-parser.js - Added @match parser
  • src/background/style-manager/matcher.js - Enhanced matching
  • src/background/usercss-manager.js - Updated usercss handling
  • src/js/usercss-compiler.js - Added @match compilation
  • src/js/sections-util.js - Better sections processing
  • src/js/prefs.js - Enhanced preferences
  • src/install-usercss/index.js - Added @match support and favicon display
  • src/manage/ files - UI updates and @match display

- Implemented URL pattern matching functionality for @match directives
- Added support for domains with hyphens in pattern matching
- Fixed regex pattern to properly parse domains like aflt-systems.ru
- Updated urlMatchPattern function to handle subdomain wildcards correctly
@bezustally bezustally force-pushed the feat/match-directive-support branch from 9184c5d to 5aaecb9 Compare September 8, 2025 12:25
import {ownRoot} from '@/js/urls';
import {stringAsRegExpStr, tryRegExp, tryURL} from '@/js/util';
import * as colorScheme from '../color-scheme';
import { styleCodeEmpty } from "@/js/sections-util";
Copy link
Member

Choose a reason for hiding this comment

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

Please undo all cosmetic changes (formatting/quotes/indents and so on) as it makes next to impossible to use git features like blame or history grep or diff as they become too "noisy" in almost any git client.

Copy link
Author

Choose a reason for hiding this comment

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

@tophf Is it better now?

Copy link
Member

Choose a reason for hiding this comment

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

Almost. There's still prefs.js and manage-newui.css.

@bezustally bezustally force-pushed the feat/match-directive-support branch from c730e3e to 292f48a Compare September 8, 2025 16:55
- Revert formatting changes (quotes, spacing, line breaks) in all modified files
- Preserve functional changes for @match directive support
- Keep original code style to avoid git history noise
- Affected files: matcher.js, usercss-manager.js, install-usercss/index.js, meta-parser.js, sections-util.js, usercss-compiler.js, render-favs.js, render.js
@bezustally bezustally force-pushed the feat/match-directive-support branch from 292f48a to 19ecb24 Compare September 8, 2025 16:55
Copy link
Member

@tophf tophf left a comment

Choose a reason for hiding this comment

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

While I found some more trivial issues in the code, it can wait until we decide on the high-level design in #2002.

const {sourceCode: code, [UCD]: {vars, preprocessor, match}} = style;

// Pass @match data to compiler
const varsWithMatch = vars
Copy link
Member

Choose a reason for hiding this comment

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

AFAIK this is the same as const varsWithMatch = {...vars, _usercssData: {match}}

replaceChildren($('.external-link'), makeExternalLink());
getAppliesTo().then(list =>
replaceChildren($('.applies-to'), list.map(s => $create('li', s))));
replaceChildren($('.applies-to'), list.map(s => {
Copy link
Member

Choose a reason for hiding this comment

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

  1. We shouldn't show favicons if the user disables the option to show favicons in the manager (usually for privacy).
  2. We should reuse the existing code that shows icons for all targets, not just @match.
  3. Since this is not exactly trivial, maybe it should be done in a separate PR


const PREPROCESSORS = new Set(['default', 'uso', 'stylus', 'less']);

// Custom parser for @match directive
Copy link
Member

Choose a reason for hiding this comment

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

import {deepCopy, deepEqual, isCssDarkScheme, makePropertyPopProxy} from './util';
import {onStorageChanged} from './util-webext';
import './msg-init'; // installs direct `API` handler
import { k_busy } from "@/js/consts";
Copy link
Member

Choose a reason for hiding this comment

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

Formatting/syntax shouldn't be changed (in the entire file).

const res = extractSections({code});

// Process @match directives from metadata
if (vars && vars._usercssData && vars._usercssData.match) {
Copy link
Member

Choose a reason for hiding this comment

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

Use the modern syntax: vars?._usercssData?.match

padding: 0 0.5em;
display: flex;
flex-wrap: wrap;
flex-wrap: nowrap;
Copy link
Member

Choose a reason for hiding this comment

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

Why? Changes in essential things like entry styling must be convincingly justified/explained.

overflow: hidden;
max-height: calc(var(--num-targets) * 18px);
width: 100%;
display: flex;
Copy link
Member

Choose a reason for hiding this comment

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

Why?

}
.target {
display: block;
display: inline-block;
Copy link
Member

Choose a reason for hiding this comment

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

Why?

line-height: var(--target-height);
width: 0;
min-width: 100%;
width: auto;
Copy link
Member

Choose a reason for hiding this comment

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

Why?

}
}
element.dataset.type = type;
element.dataset.targetValue = targetValue; // Store original value for favicon
Copy link
Member

Choose a reason for hiding this comment

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

I don't see the necessity to have separate displayValue and target.dataset.targetValue. Looks like the renderFavs function's regexp can be changed to extract the domain from target.textContent

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.

Feature request: Add @match directive support

2 participants