Skip to content

Commit

Permalink
[IMP] owl-vision: syntax scripts, single quotes attributes and slot p…
Browse files Browse the repository at this point in the history
…rops highlight and switch below command

This commit adds the following:

- Syntax builder scripts to make syntaxes easier to read and edit
- Syntax highlight in single quote attributes
- Syntax highlight for slot props
- Basic syntax highlight for xpaths
- Added `Switch Below` command

This commit fixes the following:

- Using `Switch Besides` or `Switch Below` does not open a new panel if one was already open
- Fixed missing space in component's snippet indentation
  • Loading branch information
BastienFafchamps authored and ged-odoo committed Nov 2, 2023
1 parent 398df54 commit 34489a2
Show file tree
Hide file tree
Showing 13 changed files with 930 additions and 240 deletions.
18 changes: 16 additions & 2 deletions tools/owl-vision/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,22 @@ All notable changes to the "owl-vision" extension will be documented in this fil

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## [Unreleased] [0.0.1] - 2023-03-10
## [0.0.2] - 2023-2-11

### Added

- Switch Below command
- Basic syntax highlight for xpaths
- Syntax builder scripts to make syntaxes easier to read and edit
- Syntax highlight in single quote attributes
- Syntax highlight for slot props

### Fixed

- Added missing space in component's snippet indentation
- Using `Switch Besides` or `Switch Below` does not open a new panel if one was already open

## [0.0.1] - 2023-03-10

- Initial release

Expand All @@ -15,4 +30,3 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- `Find Component` Command - Finds the selected component definition.
- `Switch` Command - Finds the corresponding template or component file depending on the current file.
- `Switch Besides` Command - Finds the corresponding template or component file depending on the current file and opens it besides.
- `Owl Documentation` Sidebar - A webview which allows easly searching through the owl's documentation from github
11 changes: 6 additions & 5 deletions tools/owl-vision/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ Owl Vision is an extension for the amazing [Owl framework](https://github.com/od

![Syntax highlight preview](https://raw.githubusercontent.com/odoo/owl/master/tools/owl-vision/assets/syntax_highlight.png)

This extension also adds a small Component snippet to allow you to create beautiful components as fast as possible!
This extension also adds:
- A basic component snippent.
- "Go to definition" providers for component tags in xml or in inline templates.

## Commands

Expand All @@ -13,11 +15,10 @@ This extension also adds a small Component snippet to allow you to create beauti
- If the cursor is on a component, finds the template of the selected component.
* `Owl Vision: Find Component`: Finds the selected component definition.
* `Owl Vision: Switch`: Finds the corresponding template or component depending on the current file.
* `Owl Vision: Switch Besides`: Finds the corresponding template or component depending on the current file and opens it besides.
* `Owl Vision: Switch (Besides)`: Finds the corresponding template or component depending on the current file and opens it besides.
* `Owl Vision: Switch (Below)`: Finds the corresponding template or component depending on the current file and opens it below.

## Extension Settings

This extension contributes the following settings:
## Settings

* `owl-vision.include`: Glob filter for files to include while searching.
* `owl-vision.exclude`: Glob filter for files to exclude while searching.
Expand Down
15 changes: 9 additions & 6 deletions tools/owl-vision/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "Owl framework extension that highlights templates and ease navigation between components and templates.",
"publisher": "Odoo",
"license": "LGPL-3.0-only",
"version": "0.0.1",
"version": "0.0.2",
"repository": {
"type": "git",
"url": "https://github.com/odoo/owl/tree/master/tools/owl-vision"
Expand All @@ -30,7 +30,12 @@
},
{
"command": "owl-vision.switch-besides",
"title": "Switch Besides",
"title": "Switch (Besides)",
"category": "Owl Vision"
},
{
"command": "owl-vision.switch-below",
"title": "Switch (Below)",
"category": "Owl Vision"
},
{
Expand Down Expand Up @@ -74,9 +79,6 @@
"embeddedLanguages": {
"meta.embedded.block.javascript": "source.js"
},
"tokenTypes": {
"string.quoted.double.xml": "other"
},
"injectTo": [
"text.xml"
]
Expand Down Expand Up @@ -120,7 +122,8 @@
"vscode:prepublish": "npm run esbuild-base -- --minify",
"esbuild-base": "esbuild ./src/extension.ts --bundle --outfile=out/main.js --external:vscode --format=cjs --platform=node",
"esbuild": "npm run esbuild-base -- --sourcemap",
"esbuild-watch": "npm run esbuild-base -- --sourcemap --watch"
"esbuild-watch": "npm run esbuild-base -- --sourcemap --watch",
"build-syntax": "node ./scripts/owl_template_syntax.mjs"
},
"devDependencies": {
"@types/node": "20.2.5",
Expand Down
48 changes: 48 additions & 0 deletions tools/owl-vision/scripts/owl_template_syntax.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { createTagPattern, exportPatterns } from "./syntax_builder_utils.mjs";
import {
htmlAttributes,
owlAttributesDynamic,
owlAttributesFormattedString,
owlAttributesStatic,
propsAttributes
} from "./syntax_parts/owl_attributes.mjs";
import { xpathAttributes } from "./syntax_parts/xpath.mjs";

const componentsTags = createTagPattern("component-tags", {
match: "[A-Z][a-zA-Z0-9_]*",
name: "entity.name.type.class owl.component",
patterns: [
owlAttributesDynamic,
owlAttributesDynamic,
propsAttributes,
],
});

const htmlTags = createTagPattern("html-tags", {
match: "[a-z][a-zA-Z0-9_:.]+|[abiqsuw]",
name: "entity.name.tag.localname.xml owl.xml.tag",
patterns: [
owlAttributesFormattedString,
xpathAttributes,
owlAttributesDynamic,
owlAttributesStatic,
htmlAttributes,
],
});

const tTag = createTagPattern("t-tag", {
match: "t(?![a-zA-Z])",
name: "entity.name.tag.localname.xml owl.tag",
patterns: [
propsAttributes,
owlAttributesFormattedString,
owlAttributesDynamic,
owlAttributesStatic,
],
});

exportPatterns(
"L:text.xml -comment",
"owl.template",
[componentsTags, htmlTags, tTag]
);
117 changes: 117 additions & 0 deletions tools/owl-vision/scripts/syntax_builder_utils.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { writeFileSync } from "fs";
import { dirname, resolve } from "path";
import { fileURLToPath } from 'url';

const REPOSITORY = {};

export function exportPatterns(injectionSelector, scopeName, patterns) {
const data = {
injectionSelector: injectionSelector,
scopeName: scopeName,
patterns: [],
repository: {}
}

for (const pattern of patterns) {
data.patterns.push({ include: `#${pattern.id}` });
}

for (const id in REPOSITORY) {
const pattern = { ...REPOSITORY[id] };

delete pattern.id;

data.repository[id] = pattern;
}

const currentDir = dirname(fileURLToPath(import.meta.url));
const filePath = resolve(currentDir, "../syntaxes", `${scopeName}.json`);
writeFileSync(filePath, JSON.stringify(data, null, 4));
console.info(`Sucessfuly build ./syntaxes/${scopeName}.json`);
}

export function createPattern(id, { name, match, begin, end, contentName, beginCaptures, endCaptures, patterns }) {
const pattern = { ...arguments[1] };
if (id) {
pattern.id = id;
REPOSITORY[id] = pattern;
}

function mapCaptures(name, captures) {
if (!captures) {
return;
}

pattern[name] = {};
for (const key in captures) {
pattern[name][key] = { name: captures[key] }
}
}

mapCaptures("beginCaptures", beginCaptures);
mapCaptures("endCaptures", endCaptures);

pattern.patterns = [];

if (patterns) {
for (const childPattern of patterns) {
if (typeof childPattern === "string") {
pattern.patterns.push({ include: childPattern });
} else if (childPattern.id) {
pattern.patterns.push({ include: `#${childPattern.id}` });
} else {
pattern.patterns.push(childPattern);
}
}
}

return pattern;
}

export function createTagPattern(id, { match, name, patterns }) {
return createPattern(id, {
begin: `(</?)(${match})`,
beginCaptures: {
"1": "punctuation.definition.tag.xml owl.xml.punctuation",
"2": name,
},
end: "\\s*([/?]?>)",
endCaptures: {
"1": "punctuation.definition.tag.xml punctuation",
},
patterns,
});
}

export function createAttributePatterns(id, { match, attributeName, contentName = "", patterns = [] }) {
return createPattern(id, {
patterns: [
createPattern(undefined, {
contentName: contentName !== null ? (contentName + " string.quoted.double.xml").trim() : undefined,
begin: `(\\s*)(${match})(=)(")`,
beginCaptures: {
"2": "entity.other.attribute-name.localname.xml " + attributeName,
"4": "punctuation.definition.string.begin.xml",
},
end: `(")`,
endCaptures: {
"0": "punctuation.definition.string.end.xml",
},
patterns,
}),
createPattern(undefined, {
contentName: contentName !== null ? (contentName + " string.quoted.single.xml").trim() : undefined,
begin: `(\\s*)(${match})(=)(')`,
beginCaptures: {
"2": "entity.other.attribute-name.localname.xml " + attributeName,
"4": "punctuation.definition.string.begin.xml",
},
end: `(')`,
endCaptures: {
"0": "punctuation.definition.string.end.xml",
},
patterns,
})
]
});
}
103 changes: 103 additions & 0 deletions tools/owl-vision/scripts/syntax_parts/owl_attributes.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { createAttributePatterns, createPattern } from "../syntax_builder_utils.mjs";

export const inilineJs = [createPattern("inline-js", {
patterns: [
{
match: "\\s(=>)\\s",
captures: {
"1": {
name: "string.quoted.double.xml owl.arrow",
}
}
},
{
match: "\\b(props)\\b",
captures: {
"1": {
name: "variable.language.js owl.expression.props",
}
}
},
{
match: "\\s(and|or)\\s",
captures: {
"1": {
name: "keyword.operator.logical.js owl.logical",
}
}
},
{
include: "source.js"
}
]
})];

const formattedString = createPattern("formatted-string", {
contentName: "meta.embedded.block.javascript",
begin: `({{)`,
beginCaptures: {
"1": "owl.double-curlybrackets",
},
end: `(}})`,
endCaptures: {
"1": "owl.double-curlybrackets",
},
patterns: inilineJs
});

// -------------------------------- Attributes --------------------------------

export const htmlAttributes = createAttributePatterns("html-attributes", {
match: "[a-z]{2}[a-z_:.-]+",
attributeName: "owl.xml.attribute",
});

export const propsAttributes = createAttributePatterns("props-attributes", {
match: "[a-zA-Z]{2}[a-zA-Z_:.]*",
contentName: "meta.embedded.block.javascript",
attributeName: "owl.attribute owl.attribute.props",
patterns: inilineJs,
});

export const owlAttributesDynamic = createAttributePatterns("owl-attributes-dynamic", {
match: [
"t-if",
"t-else",
"t-elif",
"t-foreach",
"t-as",
"t-key",
"t-esc",
"t-out",
"t-props",
"t-component",
"t-set",
"t-value",
"t-portal",
"t-slot-scope",
"t-att-[a-z_:.-]+",
"t-on-[a-z_:.-]+"
].join("|"),
contentName: "meta.embedded.block.javascript",
attributeName: "owl.attribute owl.attribute.dynamic",
patterns: inilineJs,
});

export const owlAttributesStatic = createAttributePatterns("owl-attributes-static", {
match: [
"t-name",
"t-ref",
"t-set-slot",
"t-model",
"t-inherit",
"t-inherit-mode",
"t-translation"
].join("|"),
attributeName: "owl.attribute owl.attribute.static",
});

export const owlAttributesFormattedString = createAttributePatterns("owl-attributes-formatted-string", {
match: ["t-call", "t-slot", "t-attf-[a-z_:.-]+"].join("|"),
attributeName: "owl.attribute owl.attribute.formatted",
patterns: [formattedString],
});
Loading

0 comments on commit 34489a2

Please sign in to comment.