From 6c9ad48d1195ec92cad6265a6deb6c263cd801d5 Mon Sep 17 00:00:00 2001 From: James J Balamuta Date: Sun, 28 Apr 2024 16:32:39 -0700 Subject: [PATCH] Initializing gh-pages branch --- .devcontainer/devcontainer.json | 36 ++++++ .github/workflows/publish-website.yml | 31 +++++ .gitignore | 5 + README.md | 71 ++++++++++++ _extensions/codecelloptions/_extension.yml | 8 ++ .../codecelloptions.code-workspace | 8 ++ .../codecelloptions/codecelloptions.lua | 108 ++++++++++++++++++ 7 files changed, 267 insertions(+) create mode 100644 .devcontainer/devcontainer.json create mode 100644 .github/workflows/publish-website.yml create mode 100644 .gitignore create mode 100644 README.md create mode 100644 _extensions/codecelloptions/_extension.yml create mode 100644 _extensions/codecelloptions/codecelloptions.code-workspace create mode 100644 _extensions/codecelloptions/codecelloptions.lua diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..7eeff4e --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,36 @@ +// Config options: https://github.com/rocker-org/devcontainer-templates/tree/main/src/r-ver +{ + "name": "R (rocker/r-ver base)", + "image": "ghcr.io/rocker-org/devcontainer/r-ver:4.3", + // Add software + "features": { + // Required to test with knitr + // R package config: https://github.com/rocker-org/devcontainer-features/blob/main/src/r-rig/README.md + "ghcr.io/rocker-org/devcontainer-features/r-rig:1": { + "version": "none", + "installRMarkdown": true, + "installJupyterlab": true, + "installRadian": true + }, + // You may wish to switch prerelease to latest for stable development + // Quarto configuration : https://github.com/rocker-org/devcontainer-features/blob/main/src/quarto-cli/README.md + "ghcr.io/rocker-org/devcontainer-features/quarto-cli:1": { + "installTinyTex": true, + "version": "prerelease" + } + }, + "customizations": { + "vscode": { + "settings": { + "r.rterm.linux": "/usr/local/bin/radian", + "r.bracketedPaste": true, + "r.plot.useHttpgd": true, + "[r]": { + "editor.wordSeparators": "`~!@#%$^&*()-=+[{]}\\|;:'\",<>/?" + } + }, + // Enable a development set of extensions for Lua and Quarto + "extensions": ["quarto.quarto", "sumneko.lua", "GitHub.copilot"] + } + } +} diff --git a/.github/workflows/publish-website.yml b/.github/workflows/publish-website.yml new file mode 100644 index 0000000..6bfb1f7 --- /dev/null +++ b/.github/workflows/publish-website.yml @@ -0,0 +1,31 @@ +on: + push: + branches: [main, master] + release: + types: [published] + workflow_dispatch: {} + +name: demo-page + +jobs: + demo-page: + runs-on: ubuntu-latest + # Only restrict concurrency for non-PR jobs + concurrency: + group: quarto-publish-${{ github.event_name != 'pull_request' || github.run_id }} + permissions: + contents: write + steps: + - name: "Check out repository" + uses: actions/checkout@v4 + + - name: "Set up Quarto" + uses: quarto-dev/quarto-actions/setup@v2 + with: + version: "pre-release" + + - name: Publish to GitHub Pages (and render) + uses: quarto-dev/quarto-actions/publish@v2 + with: + target: gh-pages + path: docs \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4a32947 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.html +*.pdf +*_files/ +/.luarc.json +.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 0000000..0258943 --- /dev/null +++ b/README.md @@ -0,0 +1,71 @@ +# codecelloptions: A Quarto Experiment on Options + +The `codecelloptions` extension is a Quarto extension designed to improve working with custom code cells and cell options in Quarto. + +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/coatless-quarto/codecelloptions) + +## Usage + +The `codecelloptions` extension does not introduce significant enhancements to your document's content. Instead, it serves as a way for authors to quickly bootstrap their own custom code cell through an [extension embedding](https://quarto.org/docs/journals/formats.html#extension-embedding). + +## Installation + +To install the `codecelloptions` extension inside of your own extension, follow these steps: + +1. Open your terminal. + +2. Navigate to where your own extension's development location is. + +3. Execute the following command: + +```sh +quarto add coatless-quarto/codecelloptions --embed +``` + +This command will download and install the extension under the `_extensions` subdirectory of your Quarto extension project. If you are using version control, ensure that you include this directory in your repository. + +### File structure + +When embedding the extension inside of your own extension, you should see the following folder structure: + +```sh +. +└── _extensions + └── + └── _extensions + └── coatless-quarto + └── cellcodeoptions + +``` + +### Registering the extension + +Inside of the `_extension.yml`, please include the nested extension under `filters` as the first extension to run: + +``` +title: My Extension +author: My Name +version: 0.1.1 +quarto-required: ">=1.4.549" +contributes: + format: + common: + filters: + - coatless-quarto/cellcodeoptions + - .lua +``` + +## Options + +The extension allows for extracting options from the hashpipe-styled commands, e.g. + +````md +```{custom-python} +#| option1: value1 +#| option2: value2 + +# code here +``` +```` + +You cannot extract options given in `inline` within the code cell engine declaration; nor should you. diff --git a/_extensions/codecelloptions/_extension.yml b/_extensions/codecelloptions/_extension.yml new file mode 100644 index 0000000..488c30e --- /dev/null +++ b/_extensions/codecelloptions/_extension.yml @@ -0,0 +1,8 @@ +title: Code Cell Options +author: James Balamuta +version: 0.0.1-dev.0 +quarto-required: ">=1.4.549" +contributes: + filters: + - codecelloptions.lua + diff --git a/_extensions/codecelloptions/codecelloptions.code-workspace b/_extensions/codecelloptions/codecelloptions.code-workspace new file mode 100644 index 0000000..407c760 --- /dev/null +++ b/_extensions/codecelloptions/codecelloptions.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "../.." + } + ], + "settings": {} +} \ No newline at end of file diff --git a/_extensions/codecelloptions/codecelloptions.lua b/_extensions/codecelloptions/codecelloptions.lua new file mode 100644 index 0000000..930524d --- /dev/null +++ b/_extensions/codecelloptions/codecelloptions.lua @@ -0,0 +1,108 @@ +-- Check if variable missing or an empty string +local function isVariableEmpty(s) + return s == nil or s == '' +end + +-- Copy the top level value and its direct children +-- Details: http://lua-users.org/wiki/CopyTable +local function shallowcopy(original) + -- Determine if its a table + if type(original) == 'table' then + -- Copy the top level to remove references + local copy = {} + for key, value in pairs(original) do + copy[key] = value + end + -- Return the copy + return copy + else + -- If original is not a table, return it directly since it's already a copy + return original + end +end + +-- Custom method for cloning a table with a shallow copy. +function table.clone(original) + return shallowcopy(original) +end + +local function mergeCellOptions(localOptions, defaultOptions) + -- Copy default options to the mergedOptions table + local mergedOptions = table.clone(defaultOptions) + + -- Override default options with local options + for key, value in pairs(localOptions) do + if type(value) == "string" then + value = value:gsub("[\"']", "") + end + mergedOptions[key] = value + end + + -- Return the customized options + return mergedOptions +end + +-- Remove lines with only whitespace until the first non-whitespace character is detected. +local function removeEmptyLinesUntilContent(codeText) + -- Iterate through each line in the codeText table + for _, value in ipairs(codeText) do + -- Detect leading whitespace (newline, return character, or empty space) + local detectedWhitespace = string.match(value, "^%s*$") + + -- Check if the detectedWhitespace is either an empty string or nil + -- This indicates whitespace was detected + if isVariableEmpty(detectedWhitespace) then + -- Delete empty space + table.remove(codeText, 1) + else + -- Stop the loop as we've now have content + break + end + end + + -- Return the modified table + return codeText +end + +-- Extract Quarto code cell options from the block's text +local function extractCodeBlockOptions(block) + + -- Access the text aspect of the code block + local code = block.text + + -- Define two local tables: + -- the block's attributes + -- the block's code lines + local cellOptions = {} + local newCodeLines = {} + + -- Iterate over each line in the code block + for line in code:gmatch("([^\r\n]*)[\r\n]?") do + -- Check if the line starts with "#|" and extract the key-value pairing + -- e.g. #| key: value goes to cellOptions[key] -> value + local key, value = line:match("^#|%s*(.-):%s*(.-)%s*$") + + -- If a special comment is found, then add the key-value pairing to the cellOptions table + if key and value then + cellOptions[key] = value + else + -- Otherwise, it's not a special comment, keep the code line + table.insert(newCodeLines, line) + end + end + + -- Merge cell options with default options + cellOptions = mergeCellOptions(cellOptions) + + -- Set the codeblock text to exclude the special comments. + cellCode = table.concat(newCodeLines, '\n') + + -- Return the code alongside options + return cellCode, cellOptions +end + +return { + removeEmptyLinesUntilContent = removeEmptyLinesUntilContent, + extractCodeBlockOptions = extractCodeBlockOptions, + mergeCellOptions = mergeCellOptions +} \ No newline at end of file