jupyterlab-makefile-file-type-extension 1.0.6__tar.gz → 1.0.67__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jupyterlab_makefile_file_type_extension-1.0.67/.claude/JOURNAL.md +50 -0
- jupyterlab_makefile_file_type_extension-1.0.67/.claude/settings.local.json +38 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/Makefile +2 -2
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/PKG-INFO +1 -1
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/jupyterlab_makefile_file_type_extension/_version.py +1 -1
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/jupyterlab_makefile_file_type_extension/labextension/package.json +3 -3
- jupyterlab_makefile_file_type_extension-1.0.67/jupyterlab_makefile_file_type_extension/labextension/static/207.badae462452695117055.js +1 -0
- jupyterlab_makefile_file_type_extension-1.0.67/jupyterlab_makefile_file_type_extension/labextension/static/remoteEntry.27752a82fa0295af2768.js +1 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/package-lock.json +3 -3
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/package.json +2 -2
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/src/index.ts +14 -16
- jupyterlab_makefile_file_type_extension-1.0.67/src/makefile-mode-simple.ts +227 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/src/makefile-mode.ts +75 -25
- jupyterlab_makefile_file_type_extension-1.0.67/test-parser.js +209 -0
- jupyterlab_makefile_file_type_extension-1.0.67/test-tokenize-lines.js +206 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/yarn.lock +2165 -2165
- jupyterlab_makefile_file_type_extension-1.0.6/.claude/JOURNAL.md +0 -29
- jupyterlab_makefile_file_type_extension-1.0.6/.claude/settings.local.json +0 -21
- jupyterlab_makefile_file_type_extension-1.0.6/jupyterlab_makefile_file_type_extension/labextension/static/575.f4493e75c54f17e3b4a5.js +0 -1
- jupyterlab_makefile_file_type_extension-1.0.6/jupyterlab_makefile_file_type_extension/labextension/static/remoteEntry.3b34b172c4b557d26b23.js +0 -1
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/.claude/CLAUDE.md +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/.copier-answers.yml +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/.git +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/.gitignore +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/.prettierignore +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/.resources/screenshot.png +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/.yarnrc.yml +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/CHANGELOG.md +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/LICENSE +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/README.md +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/RELEASE.md +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/babel.config.js +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/install.json +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/jest.config.js +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/jupyterlab_makefile_file_type_extension/__init__.py +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/jupyterlab_makefile_file_type_extension/labextension/static/728.1918bf9a0180bf411ce7.js +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/jupyterlab_makefile_file_type_extension/labextension/static/style.js +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/jupyterlab_makefile_file_type_extension/labextension/static/third-party-licenses.json +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/pyproject.toml +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/setup.py +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/src/__tests__/jupyterlab_makefile_file_type_extension.spec.ts +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/style/base.css +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/style/index.css +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/style/index.js +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/tsconfig.json +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/tsconfig.test.json +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/ui-tests/README.md +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/ui-tests/jupyter_server_test_config.py +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/ui-tests/package.json +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/ui-tests/playwright.config.js +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/ui-tests/tests/jupyterlab_makefile_file_type_extension.spec.ts +0 -0
- {jupyterlab_makefile_file_type_extension-1.0.6 → jupyterlab_makefile_file_type_extension-1.0.67}/ui-tests/yarn.lock +0 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Claude Code Journal
|
|
2
|
+
|
|
3
|
+
This journal tracks substantive work on documents, diagrams, and documentation content.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
1. **Task - Custom Makefile Syntax Highlighter**: Implemented custom CodeMirror language mode for Makefile syntax highlighting<br>
|
|
8
|
+
**Result**: Created `src/makefile-mode.ts` with comprehensive token recognition for targets, variable assignments, recipe lines, shell commands, and variable references. Replaced generic CMake mode with Makefile-specific parser that properly handles Make syntax constructs.
|
|
9
|
+
|
|
10
|
+
2. **Task - Variable Reference Coloring**: Implemented distinct styling for different variable reference types<br>
|
|
11
|
+
**Result**: Make-style variables `$(VAR)` highlighted with strong emphasis, shell-style variables `${VAR}` highlighted as special, automatic variables `$@`, `$<`, etc. highlighted distinctly. Added recognition for Make functions like `$(shell ...)`, `$(wildcard ...)`, `$(patsubst ...)`.
|
|
12
|
+
|
|
13
|
+
3. **Task - String Parsing Priority**: Fixed string handling to parse quoted text correctly before other tokens<br>
|
|
14
|
+
**Result**: Moved string detection to top of token parser flow, ensuring single and double quoted strings are properly recognized and highlighted throughout Makefile content including in variable assignments and recipe commands.
|
|
15
|
+
|
|
16
|
+
4. **Task - Line Continuation Highlighting**: Added distinct highlighting for backslash line continuations<br>
|
|
17
|
+
**Result**: Implemented detection of backslash at end of line with `keyword.control escape` styling. Regular backslashes in middle of text remain unstyled, ensuring only true line continuations stand out visually.
|
|
18
|
+
|
|
19
|
+
5. **Task - Custom File Type Icon**: Designed and implemented pale red settings/gear icon for Makefile files<br>
|
|
20
|
+
**Result**: Created SVG settings icon with pale red color (#ef9a9a) to represent build/make files. Added pattern field to file type registration to match `Makefile`, `makefile`, `GNUmakefile` filenames. Icon displays in JupyterLab file browser.
|
|
21
|
+
|
|
22
|
+
6. **Task - Makefile Upgrade Target**: Extended project Makefile with upgrade target for dependency management<br>
|
|
23
|
+
**Result**: Added `upgrade` target dependent on `check_dependencies` that executes `npm update`, `yarn install`, and `yarn upgrade`. Updated `.PHONY` declarations and bumped Makefile version to 1.25.
|
|
24
|
+
|
|
25
|
+
7. **Task - Icon Refinement to VS Code Style**: Replaced settings gear icon with bold capital M letter matching VS Code design<br>
|
|
26
|
+
**Result**: Implemented SVG text-based icon featuring bold (font-weight 900) capital letter "M" in pale red color. Initial color #ef9a9a adjusted to slightly redder #e57373 for better visibility and brand consistency with VS Code Makefile icon style.
|
|
27
|
+
|
|
28
|
+
8. **Task - Icon Color Optimization**: Fine-tuned M icon color for improved visibility and aesthetic appeal<br>
|
|
29
|
+
**Result**: Progressively refined icon color from #e57373 to darker and more saturated #d84a4a, achieving better contrast and visual prominence in JupyterLab file browser while maintaining the recognizable red color scheme associated with Makefile icons. Version bumped to 1.0.2 to mark stable release.
|
|
30
|
+
|
|
31
|
+
9. **Task - String Quote Matching Fix**: Resolved bug where double-quoted strings incorrectly closed on single quotes<br>
|
|
32
|
+
**Result**: Separated string parsing logic into distinct code blocks for double quotes and single quotes. Each block now explicitly matches only its corresponding closing quote character, preventing cross-quote-type matching. Enhanced color distinction for `$(VAR)` Make-style and `${VAR}` shell-style variable references with comments clarifying the semantic differences.
|
|
33
|
+
|
|
34
|
+
10. **Task - Shell Command String Handling**: Fixed incorrect string parsing inside `$(shell ...)` and other Make function constructs<br>
|
|
35
|
+
**Result**: Implemented parenthesis depth tracking with state variable `parenDepth`. When inside `$(...)` constructs (depth > 0), quotes are treated as literal characters with `atom` token type instead of string delimiters. The `$(` and `)` markers receive `processingInstruction` token for visual distinction. Reset depth at start of each line. This prevents strings within shell commands from breaking syntax highlighting while allowing normal parsing for other tokens.
|
|
36
|
+
|
|
37
|
+
11. **Task - Build Process Improvements and Debugging**: Identified and resolved build caching and version consistency issues<br>
|
|
38
|
+
**Result**: Discovered TypeScript compilation requires lib directory to exist before `jupyter labextension build` runs. Webpack caching can cause mixed version numbers in logs. Recommended build process: (1) `npm run build:lib:prod` to compile TypeScript to lib/, (2) `jupyter labextension build . --development False` to bundle extension, (3) `pip install -e . --force-reinstall --no-deps` to install Python package. For clean rebuilds, remove lib/ and labextension/ directories first. Added extensive console logging with version numbers to track parser activation and identify MIME type conflicts. Extension supports `.mk`, `.mak`, `.make`, `.makefile` extensions plus filename patterns for `Makefile`, `makefile`, `GNUmakefile`.
|
|
39
|
+
|
|
40
|
+
12. **Task - .mk File Syntax Highlighting**: Resolved issue where `.mk` files opened in editor but received no syntax highlighting<br>
|
|
41
|
+
**Result**: Investigated JupyterLab source code to understand file-to-language mapping flow. Discovered two separate pattern registrations required: (1) File type pattern in `app.docRegistry.addFileType()` for icon display and file recognition, (2) Language filename pattern in `languages.addLanguage()` for syntax highlighting. The language registry's `findByFileName()` method checks filename regex BEFORE falling back to extension matching. Root cause was language registration using pattern `^(Makefile|makefile|GNUmakefile|makefile\\..*) which matched standard Makefile names but NOT `*.mk` files. Fixed by updating both patterns to `^(Makefile|makefile|GNUmakefile|makefile\\..*|.*\\.(mk|mak|make|makefile)) ensuring consistent matching across file type and language registries. Confirmed working in v1.0.24 with proper syntax highlighting for all Makefile extensions.
|
|
42
|
+
|
|
43
|
+
13. **Task - String Parsing Fixes**: Fixed critical bugs in string handling both outside and inside `$(...)` constructs<br>
|
|
44
|
+
**Result**: First bug - strings OUTSIDE `$(...)` constructs: double-quoted strings were incorrectly closing on single quote characters and vice versa. This occurred in regular Makefile variable assignments and recipe commands. Fixed by separating string parsing logic into completely distinct code blocks for double quotes (lines 169-178) and single quotes (lines 179-188), each explicitly matching only its corresponding closing quote character. Each block has its own `while (!stream.eol())` loop that breaks only on the matching quote. Second bug - strings INSIDE `$(...)` constructs: string parsing logic was executing before `$(...)` construct detection, causing quotes within shell commands to break syntax highlighting. Implemented parenthesis depth tracking using `parenDepth` state variable. Reordered parser checks to detect `$(` pattern BEFORE string handling. Added separate string handling for inside constructs (lines 146-167) where `parenDepth > 0`. Inside constructs, quotes are treated as literal characters with same token type (`property`) as surrounding content instead of string delimiters. The `$(` increments depth, `)` decrements depth, and nested parentheses are tracked correctly. Reset depth at start of each new line. This solution maintains proper string highlighting outside constructs while preventing string parsing from interfering with shell command content. Both blocks handle escape sequences with `if (n === '\\') stream.next()` to skip escaped characters. Fixed in versions leading to v1.0.44 tagged as `SYNTAX_HIGHLIGHT_BASIC_STABLE_v1.0.44`.
|
|
45
|
+
|
|
46
|
+
14. **Task - Enhanced Makefile Syntax Support**: Implemented comprehensive syntax highlighting for targets, variables, and shell constructs<br>
|
|
47
|
+
**Result**: Added target recognition with `keyword.control strong` styling for build targets (e.g., `build:`). Implemented `.PHONY` and special target recognition as `builtin`. Changed `$(...)` construct coloring from `processingInstruction` through multiple token types (`meta`, `builtin`, `type`, `namespace`) to final `property` token type for optimal visual distinction. Added support for `$$VARIABLE` environment variables and `$$(...)` shell command substitution with proper depth tracking. Implemented `$$((expression))` arithmetic expansion with special handling for double closing parentheses. Added target dependency highlighting as `processingInstruction` for dependencies listed after colon on target lines. Tagged as STABLE_v1.0.64.
|
|
48
|
+
|
|
49
|
+
15. **Task - Recipe Command @ Prefix Support**: Added syntax highlighting for silent recipe commands with @ prefix<br>
|
|
50
|
+
**Result**: Implemented recognition of recipe commands starting with tab followed by `@` prefix (e.g., ` @echo`, ` @mkdir`). Both the `@` symbol and the command name are highlighted together as `builtin` token type, providing visual distinction for silent commands that don't echo during make execution. Commented out all debug console.log statements for production use. Version 1.0.66.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(npm run build:lib:prod:*)",
|
|
5
|
+
"Bash(yarn install)",
|
|
6
|
+
"Bash(git add:*)",
|
|
7
|
+
"Bash(cat:*)",
|
|
8
|
+
"Bash(git commit:*)",
|
|
9
|
+
"Bash(git push)",
|
|
10
|
+
"Bash(curl:*)",
|
|
11
|
+
"Bash(git rebase:*)",
|
|
12
|
+
"Bash(git stash:*)",
|
|
13
|
+
"Bash(GIT_SEQUENCE_EDITOR=\"sed -i ''1s/^pick/reword/''\" git rebase -i --root)",
|
|
14
|
+
"Bash(git filter-branch:*)",
|
|
15
|
+
"Bash(git push:*)",
|
|
16
|
+
"Bash(git tag:*)",
|
|
17
|
+
"Bash(jlpm run build:*)",
|
|
18
|
+
"Bash(pip install:*)",
|
|
19
|
+
"Bash(jupyter labextension build:*)",
|
|
20
|
+
"Bash(jupyter lab clean:*)",
|
|
21
|
+
"Bash(jupyter labextension:*)",
|
|
22
|
+
"Bash(rm:*)",
|
|
23
|
+
"Bash(npx tsc:*)",
|
|
24
|
+
"Bash(mkdir:*)",
|
|
25
|
+
"Bash(python:*)",
|
|
26
|
+
"WebFetch(domain:github.com)",
|
|
27
|
+
"Bash(node test-parser.js:*)",
|
|
28
|
+
"Bash(node test-tokenize-lines.js:*)",
|
|
29
|
+
"Bash(tokenization-results.md)",
|
|
30
|
+
"Bash(git checkout:*)",
|
|
31
|
+
"Bash(npm version:*)",
|
|
32
|
+
"Bash(git switch:*)",
|
|
33
|
+
"Bash(git rm:*)"
|
|
34
|
+
],
|
|
35
|
+
"deny": [],
|
|
36
|
+
"ask": []
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Makefile for Jupyterlab extensions version 1.25
|
|
2
|
-
# author: Stellars Henson <konrad.jelen@gmail.com
|
|
2
|
+
# author: Stellars Henson <konrad.jelen@gmail.com>
|
|
3
3
|
# License: MIT Open Source License
|
|
4
4
|
|
|
5
5
|
.PHONY: build install clean uninstall publish dependencies mrproper increment_version install_dependencies check_dependencies upgrade help
|
|
@@ -22,7 +22,7 @@ increment_version:
|
|
|
22
22
|
build: clean increment_version check_dependencies
|
|
23
23
|
npm install
|
|
24
24
|
yarn install
|
|
25
|
-
python -m build
|
|
25
|
+
python -m build
|
|
26
26
|
|
|
27
27
|
## install package
|
|
28
28
|
install: build
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jupyterlab_makefile_file_type_extension
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.67
|
|
4
4
|
Summary: Jupyterlab extension to add handling of Makefiles and syntax colouring support
|
|
5
5
|
Project-URL: Homepage, https://github.com/stellarshenson/jupyterlab_makefile_file_type_extension
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/stellarshenson/jupyterlab_makefile_file_type_extension/issues
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jupyterlab_makefile_file_type_extension",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.67",
|
|
4
4
|
"description": "Jupyterlab extension to add handling of Makefiles and syntax colouring support",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"jest": "^29.2.0",
|
|
81
81
|
"npm-run-all2": "^7.0.1",
|
|
82
82
|
"prettier": "^3.0.0",
|
|
83
|
-
"rimraf": "^5.0.
|
|
83
|
+
"rimraf": "^5.0.10",
|
|
84
84
|
"source-map-loader": "^1.0.2",
|
|
85
85
|
"style-loader": "^3.3.1",
|
|
86
86
|
"stylelint": "^15.10.1",
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
"extension": true,
|
|
104
104
|
"outputDir": "jupyterlab_makefile_file_type_extension/labextension",
|
|
105
105
|
"_build": {
|
|
106
|
-
"load": "static/remoteEntry.
|
|
106
|
+
"load": "static/remoteEntry.27752a82fa0295af2768.js",
|
|
107
107
|
"extension": "./extension",
|
|
108
108
|
"style": "./style"
|
|
109
109
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(self.webpackChunkjupyterlab_makefile_file_type_extension=self.webpackChunkjupyterlab_makefile_file_type_extension||[]).push([[207],{207:(e,t,a)=>{a.r(t),a.d(t,{default:()=>r,makefileIcon:()=>o});var n=a(337),i=a(694),l=a(84);const s={name:"makefile",startState:()=>({parenDepth:0,lastLineStart:-1,lastLineText:"",lineTokens:[]}),token:(e,t)=>{const a=e.peek(),n=e.pos,i=e.string||"",l=e.lineStart||0;l!==t.lastLineStart&&(t.parenDepth=0,t.lastLineStart=l,t.lastLineText=i,t.lineTokens=[]);let s=null;if("#"===a)e.skipToEnd(),s="comment";else if(e.sol()&&e.match(/^\t@[a-zA-Z_][a-zA-Z0-9_-]*/,!1))e.match(/^\t/),e.match(/^@/),e.match(/^[a-zA-Z_][a-zA-Z0-9_-]*/),s="builtin";else if(e.sol()&&e.match(/^\.[A-Z_]+/,!1))e.match(/^\.[A-Z_]+/),s="builtin";else if(e.sol()&&e.match(/^[A-Z_][A-Z0-9_]*/,!1))e.match(/^[A-Z_][A-Z0-9_]*/)&&e.match(/\s*[:?+]?=/,!1)?(e.match(/\s*[:?+]?=/),s="variableName.definition strong"):s=null;else if(e.sol()&&e.match(/^[a-zA-Z0-9_\-\.]+:/,!1))s=e.match(/^[a-zA-Z0-9_\-\.]+/)?"keyword.control strong":null;else if(e.sol()||!i.match(/^[a-zA-Z0-9_\-\.]+:/)||"#"===a||e.eol())if(e.match(/[:?+]?=/))s="operator";else if(e.match(/:/))s="operator";else if("$"===a&&e.match(/\$\$\(\(/,!1))e.next(),e.next(),e.next(),e.next(),t.parenDepth+=2,s="property";else if("$"===a&&e.match(/\$\$\(/,!1))e.next(),e.next(),e.next(),t.parenDepth++,s="property";else if("$"===a&&e.match(/\$\(/,!1))e.next(),e.next(),t.parenDepth++,s="property";else if("$"===a&&e.match(/\$\$[a-zA-Z_][a-zA-Z0-9_]*/,!1))e.match(/\$\$[a-zA-Z_][a-zA-Z0-9_]*/),s="property";else if("("===a&&t.parenDepth>0)t.parenDepth++,e.next(),s=null;else if(")"===a&&t.parenDepth>0){const a=e.peek();t.parenDepth--,e.next(),s=0===t.parenDepth||1===t.parenDepth&&")"===a?"property":null}else if(t.parenDepth>0)if('"'===a){for(e.next();!e.eol();){const t=e.next();if('"'===t)break;"\\"===t&&e.next()}s="property"}else if("'"===a){for(e.next();!e.eol();){const t=e.next();if("'"===t)break;"\\"===t&&e.next()}s="property"}else e.next(),s="property";else if('"'===a){for(e.next();!e.eol();){const t=e.next();if('"'===t)break;"\\"===t&&e.next()}s="string"}else if("'"===a){for(e.next();!e.eol();){const t=e.next();if("'"===t)break;"\\"===t&&e.next()}s="string"}else e.next(),s=null;else{const t=i.indexOf(":");t>=0&&n>t?"#"===a?s=null:(e.next(),s="processingInstruction"):(e.next(),s=null)}const o=e.pos,r={start:n,end:o,text:i.slice(n,o),type:s};return t.lineTokens.push(r),e.eol()&&(t.lineTokens=[]),s}},o=new i.LabIcon({name:"makefile:icon",svgstr:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">\n <text x="12" y="18" font-size="20" font-weight="900" text-anchor="middle" fill="#d84a4a" font-family="Arial, sans-serif">M</text>\n</svg>'}),r={id:"jupyterlab_makefile_file_type_extension:plugin",description:"Jupyterlab extension to add handling of Makefiles and syntax colouring support",autoStart:!0,requires:[n.IEditorLanguageRegistry],activate:(e,t)=>{console.log("[jupyterlab_makefile_file_type_extension v1.0.31-debug] Extension activated!"),t.addLanguage({name:"makefile",displayName:"Makefile",mime:"text/x-makefile",extensions:[".mk",".mak",".make",".makefile"],filename:/^(Makefile|makefile|GNUmakefile|makefile\..*|.*\.(mk|mak|make|makefile))$/,support:new l.LanguageSupport(l.StreamLanguage.define(s))}),e.docRegistry.addFileType({name:"makefile",displayName:"Makefile",mimeTypes:["text/x-makefile"],extensions:[".mk",".mak",".make",".makefile"],pattern:"^(Makefile|makefile|GNUmakefile|makefile\\..*|.*\\.(mk|mak|make|makefile))$",fileFormat:"text",contentType:"file",icon:o})}}}}]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var _JUPYTERLAB;(()=>{"use strict";var e,r,t,n,o,i,a,l,u,f,s,p,d,c,h,v,m,g,b,y={513:(e,r,t)=>{var n={"./index":()=>t.e(207).then(()=>()=>t(207)),"./extension":()=>t.e(207).then(()=>()=>t(207)),"./style":()=>t.e(728).then(()=>()=>t(728))},o=(e,r)=>(t.R=r,r=t.o(n,e)?n[e]():Promise.resolve().then(()=>{throw new Error('Module "'+e+'" does not exist in container.')}),t.R=void 0,r),i=(e,r)=>{if(t.S){var n="default",o=t.S[n];if(o&&o!==e)throw new Error("Container initialization failed as it has already been initialized with a different share scope");return t.S[n]=e,t.I(n,r)}};t.d(r,{get:()=>o,init:()=>i})}},_={};function w(e){var r=_[e];if(void 0!==r)return r.exports;var t=_[e]={id:e,exports:{}};return y[e](t,t.exports,w),t.exports}w.m=y,w.c=_,w.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return w.d(r,{a:r}),r},w.d=(e,r)=>{for(var t in r)w.o(r,t)&&!w.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},w.f={},w.e=e=>Promise.all(Object.keys(w.f).reduce((r,t)=>(w.f[t](e,r),r),[])),w.u=e=>e+"."+{207:"badae462452695117055",728:"1918bf9a0180bf411ce7"}[e]+".js?v="+{207:"badae462452695117055",728:"1918bf9a0180bf411ce7"}[e],w.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),w.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},r="jupyterlab_makefile_file_type_extension:",w.l=(t,n,o,i)=>{if(e[t])e[t].push(n);else{var a,l;if(void 0!==o)for(var u=document.getElementsByTagName("script"),f=0;f<u.length;f++){var s=u[f];if(s.getAttribute("src")==t||s.getAttribute("data-webpack")==r+o){a=s;break}}a||(l=!0,(a=document.createElement("script")).charset="utf-8",w.nc&&a.setAttribute("nonce",w.nc),a.setAttribute("data-webpack",r+o),a.src=t),e[t]=[n];var p=(r,n)=>{a.onerror=a.onload=null,clearTimeout(d);var o=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),o&&o.forEach(e=>e(n)),r)return r(n)},d=setTimeout(p.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=p.bind(null,a.onerror),a.onload=p.bind(null,a.onload),l&&document.head.appendChild(a)}},w.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{w.S={};var e={},r={};w.I=(t,n)=>{n||(n=[]);var o=r[t];if(o||(o=r[t]={}),!(n.indexOf(o)>=0)){if(n.push(o),e[t])return e[t];w.o(w.S,t)||(w.S[t]={});var i=w.S[t],a="jupyterlab_makefile_file_type_extension",l=[];return"default"===t&&((e,r,t,n)=>{var o=i[e]=i[e]||{},l=o[r];(!l||!l.loaded&&(1!=!l.eager?n:a>l.from))&&(o[r]={get:()=>w.e(207).then(()=>()=>w(207)),from:a,eager:!1})})("jupyterlab_makefile_file_type_extension","1.0.67"),e[t]=l.length?Promise.all(l).then(()=>e[t]=1):1}}})(),(()=>{var e;w.g.importScripts&&(e=w.g.location+"");var r=w.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),w.p=e})(),t=e=>{var r=e=>e.split(".").map(e=>+e==e?+e:e),t=/^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(e),n=t[1]?r(t[1]):[];return t[2]&&(n.length++,n.push.apply(n,r(t[2]))),t[3]&&(n.push([]),n.push.apply(n,r(t[3]))),n},n=(e,r)=>{e=t(e),r=t(r);for(var n=0;;){if(n>=e.length)return n<r.length&&"u"!=(typeof r[n])[0];var o=e[n],i=(typeof o)[0];if(n>=r.length)return"u"==i;var a=r[n],l=(typeof a)[0];if(i!=l)return"o"==i&&"n"==l||"s"==l||"u"==i;if("o"!=i&&"u"!=i&&o!=a)return o<a;n++}},o=e=>{var r=e[0],t="";if(1===e.length)return"*";if(r+.5){t+=0==r?">=":-1==r?"<":1==r?"^":2==r?"~":r>0?"=":"!=";for(var n=1,i=1;i<e.length;i++)n--,t+="u"==(typeof(l=e[i]))[0]?"-":(n>0?".":"")+(n=2,l);return t}var a=[];for(i=1;i<e.length;i++){var l=e[i];a.push(0===l?"not("+u()+")":1===l?"("+u()+" || "+u()+")":2===l?a.pop()+" "+a.pop():o(l))}return u();function u(){return a.pop().replace(/^\((.+)\)$/,"$1")}},i=(e,r)=>{if(0 in e){r=t(r);var n=e[0],o=n<0;o&&(n=-n-1);for(var a=0,l=1,u=!0;;l++,a++){var f,s,p=l<e.length?(typeof e[l])[0]:"";if(a>=r.length||"o"==(s=(typeof(f=r[a]))[0]))return!u||("u"==p?l>n&&!o:""==p!=o);if("u"==s){if(!u||"u"!=p)return!1}else if(u)if(p==s)if(l<=n){if(f!=e[l])return!1}else{if(o?f>e[l]:f<e[l])return!1;f!=e[l]&&(u=!1)}else if("s"!=p&&"n"!=p){if(o||l<=n)return!1;u=!1,l--}else{if(l<=n||s<p!=o)return!1;u=!1}else"s"!=p&&"n"!=p&&(u=!1,l--)}}var d=[],c=d.pop.bind(d);for(a=1;a<e.length;a++){var h=e[a];d.push(1==h?c()|c():2==h?c()&c():h?i(h,r):!c())}return!!c()},a=(e,r)=>e&&w.o(e,r),l=e=>(e.loaded=1,e.get()),u=e=>Object.keys(e).reduce((r,t)=>(e[t].eager&&(r[t]=e[t]),r),{}),f=(e,r,t)=>{var o=t?u(e[r]):e[r];return Object.keys(o).reduce((e,r)=>!e||!o[e].loaded&&n(e,r)?r:e,0)},s=(e,r,t,n)=>"Unsatisfied version "+t+" from "+(t&&e[r][t].from)+" of shared singleton module "+r+" (required "+o(n)+")",p=e=>{throw new Error(e)},d=e=>{"undefined"!=typeof console&&console.warn&&console.warn(e)},c=(e,r,t)=>t?t():((e,r)=>p("Shared module "+r+" doesn't exist in shared scope "+e))(e,r),h=(e=>function(r,t,n,o,i){var a=w.I(r);return a&&a.then&&!n?a.then(e.bind(e,r,w.S[r],t,!1,o,i)):e(r,w.S[r],t,n,o,i)})((e,r,t,n,o,u)=>{if(!a(r,t))return c(e,t,u);var p=f(r,t,n);return i(o,p)||d(s(r,t,p,o)),l(r[t][p])}),v={},m={84:()=>h("default","@codemirror/language",!1,[1,6,0,0]),337:()=>h("default","@jupyterlab/codemirror",!1,[1,4,4,10]),694:()=>h("default","@jupyterlab/ui-components",!1,[1,4,4,10])},g={207:[84,337,694]},b={},w.f.consumes=(e,r)=>{w.o(g,e)&&g[e].forEach(e=>{if(w.o(v,e))return r.push(v[e]);if(!b[e]){var t=r=>{v[e]=0,w.m[e]=t=>{delete w.c[e],t.exports=r()}};b[e]=!0;var n=r=>{delete v[e],w.m[e]=t=>{throw delete w.c[e],r}};try{var o=m[e]();o.then?r.push(v[e]=o.then(t).catch(n)):t(o)}catch(e){n(e)}}})},(()=>{var e={960:0};w.f.j=(r,t)=>{var n=w.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var o=new Promise((t,o)=>n=e[r]=[t,o]);t.push(n[2]=o);var i=w.p+w.u(r),a=new Error;w.l(i,t=>{if(w.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var o=t&&("load"===t.type?"missing":t.type),i=t&&t.target&&t.target.src;a.message="Loading chunk "+r+" failed.\n("+o+": "+i+")",a.name="ChunkLoadError",a.type=o,a.request=i,n[1](a)}},"chunk-"+r,r)}};var r=(r,t)=>{var n,o,[i,a,l]=t,u=0;if(i.some(r=>0!==e[r])){for(n in a)w.o(a,n)&&(w.m[n]=a[n]);l&&l(w)}for(r&&r(t);u<i.length;u++)o=i[u],w.o(e,o)&&e[o]&&e[o][0](),e[o]=0},t=self.webpackChunkjupyterlab_makefile_file_type_extension=self.webpackChunkjupyterlab_makefile_file_type_extension||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),w.nc=void 0;var S=w(513);(_JUPYTERLAB=void 0===_JUPYTERLAB?{}:_JUPYTERLAB).jupyterlab_makefile_file_type_extension=S})();
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jupyterlab_makefile_file_type_extension",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.67",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "jupyterlab_makefile_file_type_extension",
|
|
9
|
-
"version": "1.0.
|
|
9
|
+
"version": "1.0.67",
|
|
10
10
|
"license": "BSD-3-Clause",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@codemirror/language": "^6.0.0",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"jest": "^29.2.0",
|
|
34
34
|
"npm-run-all2": "^7.0.1",
|
|
35
35
|
"prettier": "^3.0.0",
|
|
36
|
-
"rimraf": "^5.0.
|
|
36
|
+
"rimraf": "^5.0.10",
|
|
37
37
|
"source-map-loader": "^1.0.2",
|
|
38
38
|
"style-loader": "^3.3.1",
|
|
39
39
|
"stylelint": "^15.10.1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jupyterlab_makefile_file_type_extension",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.67",
|
|
4
4
|
"description": "Jupyterlab extension to add handling of Makefiles and syntax colouring support",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"jest": "^29.2.0",
|
|
81
81
|
"npm-run-all2": "^7.0.1",
|
|
82
82
|
"prettier": "^3.0.0",
|
|
83
|
-
"rimraf": "^5.0.
|
|
83
|
+
"rimraf": "^5.0.10",
|
|
84
84
|
"source-map-loader": "^1.0.2",
|
|
85
85
|
"style-loader": "^3.3.1",
|
|
86
86
|
"stylelint": "^15.10.1",
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
import { IEditorLanguageRegistry } from '@jupyterlab/codemirror';
|
|
6
6
|
import { LabIcon } from '@jupyterlab/ui-components';
|
|
7
7
|
import { StreamLanguage, LanguageSupport } from '@codemirror/language';
|
|
8
|
-
import { makefile } from './makefile-mode';
|
|
8
|
+
import { makefileSimple as makefile } from './makefile-mode-simple';
|
|
9
9
|
|
|
10
10
|
// Import SVG icon as string - bold capital M like VS Code
|
|
11
11
|
const makefileIconStr = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
|
@@ -28,7 +28,7 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
28
28
|
requires: [IEditorLanguageRegistry],
|
|
29
29
|
activate: (app: JupyterFrontEnd, languages: IEditorLanguageRegistry) => {
|
|
30
30
|
console.log(
|
|
31
|
-
'
|
|
31
|
+
'[jupyterlab_makefile_file_type_extension v1.0.31-debug] Extension activated!'
|
|
32
32
|
);
|
|
33
33
|
|
|
34
34
|
// Register Makefile language support
|
|
@@ -36,24 +36,22 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
36
36
|
name: 'makefile',
|
|
37
37
|
displayName: 'Makefile',
|
|
38
38
|
mime: 'text/x-makefile',
|
|
39
|
-
extensions: ['.mk'],
|
|
40
|
-
filename: /^(Makefile|makefile|GNUmakefile)$/,
|
|
39
|
+
extensions: ['.mk', '.mak', '.make', '.makefile'],
|
|
40
|
+
filename: /^(Makefile|makefile|GNUmakefile|makefile\..*|.*\.(mk|mak|make|makefile))$/,
|
|
41
41
|
support: new LanguageSupport(StreamLanguage.define(makefile))
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
// Register icon for Makefile file type
|
|
45
|
-
app.docRegistry.addFileType(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
['text/x-makefile']
|
|
56
|
-
);
|
|
45
|
+
app.docRegistry.addFileType({
|
|
46
|
+
name: 'makefile',
|
|
47
|
+
displayName: 'Makefile',
|
|
48
|
+
mimeTypes: ['text/x-makefile'],
|
|
49
|
+
extensions: ['.mk', '.mak', '.make', '.makefile'],
|
|
50
|
+
pattern: '^(Makefile|makefile|GNUmakefile|makefile\\..*|.*\\.(mk|mak|make|makefile))$',
|
|
51
|
+
fileFormat: 'text' as const,
|
|
52
|
+
contentType: 'file' as const,
|
|
53
|
+
icon: makefileIcon
|
|
54
|
+
});
|
|
57
55
|
}
|
|
58
56
|
};
|
|
59
57
|
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { StreamParser } from '@codemirror/language';
|
|
2
|
+
|
|
3
|
+
export const makefileSimple: StreamParser<{
|
|
4
|
+
parenDepth: number;
|
|
5
|
+
lastLineStart: number;
|
|
6
|
+
lastLineText: string;
|
|
7
|
+
lineTokens: Array<{start: number, end: number, text: string, type: string | null}>;
|
|
8
|
+
}> = {
|
|
9
|
+
name: 'makefile',
|
|
10
|
+
|
|
11
|
+
startState: () => ({
|
|
12
|
+
parenDepth: 0,
|
|
13
|
+
lastLineStart: -1,
|
|
14
|
+
lastLineText: '',
|
|
15
|
+
lineTokens: []
|
|
16
|
+
}),
|
|
17
|
+
|
|
18
|
+
token: (stream, state) => {
|
|
19
|
+
const ch = stream.peek();
|
|
20
|
+
const startPos = stream.pos;
|
|
21
|
+
const lineText = (stream as any).string || '';
|
|
22
|
+
|
|
23
|
+
// Reset paren depth only when moving to NEW line
|
|
24
|
+
const currentLineStart = (stream as any).lineStart || 0;
|
|
25
|
+
if (currentLineStart !== state.lastLineStart) {
|
|
26
|
+
state.parenDepth = 0;
|
|
27
|
+
state.lastLineStart = currentLineStart;
|
|
28
|
+
state.lastLineText = lineText;
|
|
29
|
+
state.lineTokens = [];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let tokenType: string | null = null;
|
|
33
|
+
|
|
34
|
+
// Comments
|
|
35
|
+
if (ch === '#') {
|
|
36
|
+
stream.skipToEnd();
|
|
37
|
+
tokenType = 'comment';
|
|
38
|
+
}
|
|
39
|
+
// Recipe commands with @ prefix (e.g., @echo, @mkdir)
|
|
40
|
+
else if (stream.sol() && stream.match(/^\t@[a-zA-Z_][a-zA-Z0-9_-]*/, false)) {
|
|
41
|
+
stream.match(/^\t/); // Consume tab
|
|
42
|
+
stream.match(/^@/); // Consume @
|
|
43
|
+
stream.match(/^[a-zA-Z_][a-zA-Z0-9_-]*/); // Consume command
|
|
44
|
+
tokenType = 'builtin';
|
|
45
|
+
}
|
|
46
|
+
// Special targets (.PHONY, .DEFAULT_GOAL, etc.) - MUST check before regular targets
|
|
47
|
+
else if (stream.sol() && stream.match(/^\.[A-Z_]+/, false)) {
|
|
48
|
+
stream.match(/^\.[A-Z_]+/);
|
|
49
|
+
tokenType = 'builtin';
|
|
50
|
+
}
|
|
51
|
+
// Variable assignments (e.g., TEST := ...) - MUST check before targets
|
|
52
|
+
else if (stream.sol() && stream.match(/^[A-Z_][A-Z0-9_]*/, false)) {
|
|
53
|
+
const varName = stream.match(/^[A-Z_][A-Z0-9_]*/);
|
|
54
|
+
if (varName && stream.match(/\s*[:?+]?=/, false)) {
|
|
55
|
+
stream.match(/\s*[:?+]?=/);
|
|
56
|
+
tokenType = 'variableName.definition strong';
|
|
57
|
+
} else {
|
|
58
|
+
tokenType = null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Target definitions (e.g., build: dependencies)
|
|
62
|
+
else if (stream.sol() && stream.match(/^[a-zA-Z0-9_\-\.]+:/, false)) {
|
|
63
|
+
// Match target name only
|
|
64
|
+
const targetMatch = stream.match(/^[a-zA-Z0-9_\-\.]+/);
|
|
65
|
+
if (targetMatch) {
|
|
66
|
+
tokenType = 'keyword.control strong';
|
|
67
|
+
} else {
|
|
68
|
+
tokenType = null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Target dependencies (everything after : on target line until EOL or #)
|
|
72
|
+
else if (!stream.sol() && lineText.match(/^[a-zA-Z0-9_\-\.]+:/) && ch !== '#' && !stream.eol()) {
|
|
73
|
+
// Check if we're past the colon on a target line
|
|
74
|
+
const colonPos = lineText.indexOf(':');
|
|
75
|
+
if (colonPos >= 0 && startPos > colonPos) {
|
|
76
|
+
// Consume until end of line or comment
|
|
77
|
+
if (ch === '#') {
|
|
78
|
+
// Let comment handler take over
|
|
79
|
+
tokenType = null;
|
|
80
|
+
} else {
|
|
81
|
+
stream.next();
|
|
82
|
+
tokenType = 'processingInstruction';
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
stream.next();
|
|
86
|
+
tokenType = null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Operators
|
|
90
|
+
else if (stream.match(/[:?+]?=/)) {
|
|
91
|
+
tokenType = 'operator';
|
|
92
|
+
}
|
|
93
|
+
// Colon (for targets)
|
|
94
|
+
else if (stream.match(/:/)) {
|
|
95
|
+
tokenType = 'operator';
|
|
96
|
+
}
|
|
97
|
+
// Handle $$(( - shell arithmetic expansion (must check before $$()
|
|
98
|
+
else if (ch === '$' && stream.match(/\$\$\(\(/, false)) {
|
|
99
|
+
stream.next();
|
|
100
|
+
stream.next();
|
|
101
|
+
stream.next();
|
|
102
|
+
stream.next();
|
|
103
|
+
state.parenDepth += 2;
|
|
104
|
+
// console.log(` [DEPTH] pos=${startPos} $$(( -> depth=${state.parenDepth}`);
|
|
105
|
+
tokenType = 'property';
|
|
106
|
+
}
|
|
107
|
+
// Handle $$( - shell command substitution (must check before $()
|
|
108
|
+
else if (ch === '$' && stream.match(/\$\$\(/, false)) {
|
|
109
|
+
stream.next();
|
|
110
|
+
stream.next();
|
|
111
|
+
stream.next();
|
|
112
|
+
state.parenDepth++;
|
|
113
|
+
// console.log(` [DEPTH] pos=${startPos} $$( -> depth=${state.parenDepth}`);
|
|
114
|
+
tokenType = 'property';
|
|
115
|
+
}
|
|
116
|
+
// Handle $( - MUST come before string handling
|
|
117
|
+
else if (ch === '$' && stream.match(/\$\(/, false)) {
|
|
118
|
+
stream.next();
|
|
119
|
+
stream.next();
|
|
120
|
+
state.parenDepth++;
|
|
121
|
+
// console.log(` [DEPTH] pos=${startPos} $( -> depth=${state.parenDepth}`);
|
|
122
|
+
tokenType = 'property';
|
|
123
|
+
}
|
|
124
|
+
// Handle $$ variables (e.g., $$HOME, $$PATH, $$cols)
|
|
125
|
+
else if (ch === '$' && stream.match(/\$\$[a-zA-Z_][a-zA-Z0-9_]*/, false)) {
|
|
126
|
+
stream.match(/\$\$[a-zA-Z_][a-zA-Z0-9_]*/);
|
|
127
|
+
tokenType = 'property';
|
|
128
|
+
}
|
|
129
|
+
// Track nested ( inside $(...)
|
|
130
|
+
else if (ch === '(' && state.parenDepth > 0) {
|
|
131
|
+
state.parenDepth++;
|
|
132
|
+
stream.next();
|
|
133
|
+
// console.log(` [DEPTH] pos=${startPos} ( inside $(...) -> depth=${state.parenDepth}`);
|
|
134
|
+
tokenType = null;
|
|
135
|
+
}
|
|
136
|
+
// Track ) inside $(...)
|
|
137
|
+
else if (ch === ')' && state.parenDepth > 0) {
|
|
138
|
+
const nextCh = stream.peek();
|
|
139
|
+
state.parenDepth--;
|
|
140
|
+
stream.next();
|
|
141
|
+
// console.log(` [DEPTH] pos=${startPos} ) inside $(...) -> depth=${state.parenDepth}`);
|
|
142
|
+
// Color closing ) as property if: depth reaches 0, OR if next char is also ) and depth is 1
|
|
143
|
+
tokenType = (state.parenDepth === 0 || (state.parenDepth === 1 && nextCh === ')')) ? 'property' : null;
|
|
144
|
+
}
|
|
145
|
+
// Inside $(...) - mark everything as type
|
|
146
|
+
else if (state.parenDepth > 0) {
|
|
147
|
+
// Inside $(...)
|
|
148
|
+
if (ch === '"') {
|
|
149
|
+
stream.next();
|
|
150
|
+
while (!stream.eol()) {
|
|
151
|
+
const n = stream.next();
|
|
152
|
+
if (n === '"') break;
|
|
153
|
+
if (n === '\\') stream.next();
|
|
154
|
+
}
|
|
155
|
+
tokenType = 'property';
|
|
156
|
+
} else if (ch === "'") {
|
|
157
|
+
stream.next();
|
|
158
|
+
while (!stream.eol()) {
|
|
159
|
+
const n = stream.next();
|
|
160
|
+
if (n === "'") break;
|
|
161
|
+
if (n === '\\') stream.next();
|
|
162
|
+
}
|
|
163
|
+
tokenType = 'property';
|
|
164
|
+
} else {
|
|
165
|
+
stream.next();
|
|
166
|
+
tokenType = 'property';
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// Strings - double quote (outside $(...)
|
|
170
|
+
else if (ch === '"') {
|
|
171
|
+
stream.next();
|
|
172
|
+
while (!stream.eol()) {
|
|
173
|
+
const n = stream.next();
|
|
174
|
+
if (n === '"') break;
|
|
175
|
+
if (n === '\\') stream.next();
|
|
176
|
+
}
|
|
177
|
+
tokenType = 'string';
|
|
178
|
+
}
|
|
179
|
+
// Strings - single quote (outside $(...)
|
|
180
|
+
else if (ch === "'") {
|
|
181
|
+
stream.next();
|
|
182
|
+
while (!stream.eol()) {
|
|
183
|
+
const n = stream.next();
|
|
184
|
+
if (n === "'") break;
|
|
185
|
+
if (n === '\\') stream.next();
|
|
186
|
+
}
|
|
187
|
+
tokenType = 'string';
|
|
188
|
+
}
|
|
189
|
+
// Default - consume one character
|
|
190
|
+
else {
|
|
191
|
+
stream.next();
|
|
192
|
+
tokenType = null;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Record this token
|
|
196
|
+
const endPos = stream.pos;
|
|
197
|
+
const text = lineText.slice(startPos, endPos);
|
|
198
|
+
const tokenInfo = {
|
|
199
|
+
start: startPos,
|
|
200
|
+
end: endPos,
|
|
201
|
+
text: text,
|
|
202
|
+
type: tokenType
|
|
203
|
+
};
|
|
204
|
+
state.lineTokens.push(tokenInfo);
|
|
205
|
+
|
|
206
|
+
// If we reached end of line, flush the summary
|
|
207
|
+
if (stream.eol()) {
|
|
208
|
+
// const tokenSummary = state.lineTokens
|
|
209
|
+
// .filter(t => t.type !== null)
|
|
210
|
+
// .map(t => `[${t.start}-${t.end}] ${(t.type as string).padEnd(22)} ${t.text}`)
|
|
211
|
+
// .join('\n ');
|
|
212
|
+
|
|
213
|
+
// console.log(`\n${'='.repeat(80)}`);
|
|
214
|
+
// console.log(`LINE: ${lineText}`);
|
|
215
|
+
// console.log(`${'='.repeat(80)}`);
|
|
216
|
+
// if (tokenSummary) {
|
|
217
|
+
// console.log(` ${tokenSummary}`);
|
|
218
|
+
// }
|
|
219
|
+
// console.log(`${'='.repeat(80)}\n`);
|
|
220
|
+
|
|
221
|
+
// Clear tokens after logging
|
|
222
|
+
state.lineTokens = [];
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return tokenType;
|
|
226
|
+
}
|
|
227
|
+
};
|
|
@@ -2,22 +2,32 @@ import { StreamParser } from '@codemirror/language';
|
|
|
2
2
|
|
|
3
3
|
const variableRegex = /\$[\({][A-Za-z0-9_]+[\)}]/;
|
|
4
4
|
const shellVariableRegex = /\$\{[A-Za-z0-9_]+\}/;
|
|
5
|
-
const makeVariableRegex = /\$\([A-Za-z0-9_]+\)/;
|
|
6
5
|
|
|
7
6
|
export const makefile: StreamParser<{
|
|
8
7
|
inRecipe: boolean;
|
|
9
8
|
inComment: boolean;
|
|
9
|
+
parenDepth: number;
|
|
10
|
+
lastLineStart: number;
|
|
10
11
|
}> = {
|
|
11
12
|
name: 'makefile',
|
|
12
13
|
|
|
13
14
|
startState: () => ({
|
|
14
15
|
inRecipe: false,
|
|
15
|
-
inComment: false
|
|
16
|
+
inComment: false,
|
|
17
|
+
parenDepth: 0,
|
|
18
|
+
lastLineStart: -1
|
|
16
19
|
}),
|
|
17
20
|
|
|
18
21
|
token: (stream, state) => {
|
|
19
22
|
const ch = stream.peek();
|
|
20
23
|
|
|
24
|
+
// Reset paren depth only when moving to NEW line
|
|
25
|
+
const currentLineStart = (stream as any).lineStart || 0;
|
|
26
|
+
if (currentLineStart !== state.lastLineStart) {
|
|
27
|
+
state.parenDepth = 0;
|
|
28
|
+
state.lastLineStart = currentLineStart;
|
|
29
|
+
}
|
|
30
|
+
|
|
21
31
|
// Line continuation backslash at end of line (must be last char)
|
|
22
32
|
if (ch === '\\') {
|
|
23
33
|
const pos = stream.pos;
|
|
@@ -36,19 +46,70 @@ export const makefile: StreamParser<{
|
|
|
36
46
|
return 'comment';
|
|
37
47
|
}
|
|
38
48
|
|
|
39
|
-
//
|
|
40
|
-
if (ch === '
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
// Handle $( - MUST come before string handling
|
|
50
|
+
if (ch === '$' && stream.match(/\$\(/, false)) {
|
|
51
|
+
stream.next();
|
|
52
|
+
stream.next();
|
|
53
|
+
state.parenDepth++;
|
|
54
|
+
|
|
55
|
+
// Check for known Make functions
|
|
56
|
+
if (stream.match(/shell\b|wildcard\b|patsubst\b|filter\b|subst\b|foreach\b/, false)) {
|
|
57
|
+
stream.match(/\w+/);
|
|
58
|
+
return 'keyword';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return 'processingInstruction';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Track nested ( inside $(...)
|
|
65
|
+
if (ch === '(' && state.parenDepth > 0) {
|
|
66
|
+
state.parenDepth++;
|
|
67
|
+
stream.next();
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Track ) inside $(...)
|
|
72
|
+
if (ch === ')' && state.parenDepth > 0) {
|
|
73
|
+
state.parenDepth--;
|
|
74
|
+
stream.next();
|
|
75
|
+
return state.parenDepth === 0 ? 'processingInstruction' : null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Strings - double quote
|
|
79
|
+
if (ch === '"') {
|
|
80
|
+
const pos = stream.pos;
|
|
81
|
+
const line = (stream as any).string;
|
|
82
|
+
console.log(`[STRING] pos=${pos} depth=${state.parenDepth} char="${ch}" line="${line}"`);
|
|
83
|
+
if (state.parenDepth === 0) {
|
|
84
|
+
stream.next();
|
|
85
|
+
while (!stream.eol()) {
|
|
86
|
+
const n = stream.next();
|
|
87
|
+
if (n === '"') break;
|
|
88
|
+
if (n === '\\') stream.next();
|
|
46
89
|
}
|
|
47
|
-
|
|
48
|
-
|
|
90
|
+
console.log(`[STRING] Parsed as string, consumed to pos=${stream.pos}`);
|
|
91
|
+
return 'string';
|
|
92
|
+
} else {
|
|
93
|
+
stream.next();
|
|
94
|
+
console.log(`[STRING] Parsed as atom (inside $())`);
|
|
95
|
+
return 'atom';
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Strings - single quote
|
|
100
|
+
if (ch === "'") {
|
|
101
|
+
if (state.parenDepth === 0) {
|
|
102
|
+
stream.next();
|
|
103
|
+
while (!stream.eol()) {
|
|
104
|
+
const n = stream.next();
|
|
105
|
+
if (n === "'") break;
|
|
106
|
+
if (n === '\\') stream.next();
|
|
49
107
|
}
|
|
108
|
+
return 'string';
|
|
109
|
+
} else {
|
|
110
|
+
stream.next();
|
|
111
|
+
return 'atom';
|
|
50
112
|
}
|
|
51
|
-
return 'string';
|
|
52
113
|
}
|
|
53
114
|
|
|
54
115
|
// Recipe lines (commands starting with tab)
|
|
@@ -109,23 +170,12 @@ export const makefile: StreamParser<{
|
|
|
109
170
|
return 'keyword.control';
|
|
110
171
|
}
|
|
111
172
|
|
|
112
|
-
// Variable references
|
|
113
|
-
if (ch === '$') {
|
|
114
|
-
// Make function calls like $(shell ...), $(wildcard ...)
|
|
115
|
-
if (stream.match(/\$\(shell\b/)) {
|
|
116
|
-
return 'keyword';
|
|
117
|
-
}
|
|
118
|
-
if (stream.match(/\$\(wildcard\b|\$\(patsubst\b|\$\(filter\b|\$\(subst\b|\$\(foreach\b/)) {
|
|
119
|
-
return 'keyword';
|
|
120
|
-
}
|
|
173
|
+
// Variable references - but ONLY if we're not starting a $(...)
|
|
174
|
+
if (ch === '$' && !stream.match(/\$\(/, false)) {
|
|
121
175
|
// Shell-style variables ${VAR}
|
|
122
176
|
if (stream.match(shellVariableRegex)) {
|
|
123
177
|
return 'variableName.special';
|
|
124
178
|
}
|
|
125
|
-
// Make-style variables $(VAR)
|
|
126
|
-
if (stream.match(makeVariableRegex)) {
|
|
127
|
-
return 'variableName strong';
|
|
128
|
-
}
|
|
129
179
|
// Automatic variables $@, $<, etc.
|
|
130
180
|
if (stream.match(/\$[@<^+?*%|]/)) {
|
|
131
181
|
return 'variableName.special';
|