Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,16 @@ quote_type = single
[{Makefile,go.mod,go.sum,*.go,.gitmodules}]
indent_size = 4
indent_style = tab

[*.kt]
indent_size = 4
indent_style = space
max_line_length = 100

[*.lua]
indent_size = 2
indent_style = space

[*.el]
indent_size = 2
indent_style = space
19 changes: 10 additions & 9 deletions .github/workflows/ide_plugins.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,24 @@ jobs:

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
with:
gradle-version: 8.5

- name: Check Kotlin formatting
run: ./scripts/format_kotlin_files --check

- name: Build Plugin
working-directory: packages/jetbrains
run: ./gradlew buildPlugin
run: gradle buildPlugin

- name: Verify Plugin
working-directory: packages/jetbrains
run: ./gradlew verifyPlugin
run: gradle verifyPlugin

- name: Publish Plugin
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && contains(github.event.head_commit.modified, 'packages/jetbrains/src/main/resources/META-INF/plugin.xml')
working-directory: packages/jetbrains
run: ./gradlew publishPlugin
run: gradle publishPlugin
env:
PUBLISH_TOKEN: ${{ secrets.JETBRAINS_TOKEN }}

Expand All @@ -69,12 +74,8 @@ jobs:
# Simple check for syntax validity
- uses: actions/checkout@v4

- name: Check Lua syntax
uses: JohnnyMorganz/stylua-action@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
version: latest
args: --check packages/vim/lua/
- name: Check Lua formatting
run: ./scripts/format_lua_files --check

emacs:
name: Emacs Mode
Expand Down
16 changes: 16 additions & 0 deletions examples/features.prompt
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0

---
model: googleai/gemini-pro
input:
Expand Down
77 changes: 63 additions & 14 deletions packages/emacs/dotprompt-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -57,26 +57,75 @@

(defvar dotprompt-font-lock-keywords
(list
;; License header comments (lines starting with #)
'("^#.*$" . font-lock-comment-face)
;; YAML frontmatter delimiters
'("^---$" . font-lock-preprocessor-face)

;; YAML keys in frontmatter (word followed by colon at start of line or after indentation)
'("^\\s-*\\([a-zA-Z_][a-zA-Z0-9_-]*\\):" 1 font-lock-keyword-face)

;; YAML string values (unquoted, after colon and space)
'(":\\s-+\\([a-zA-Z][a-zA-Z0-9._/-]*\\)$" 1 font-lock-string-face)

;; YAML numeric values
'(":\\s-+\\([0-9]+\\.?[0-9]*\\)$" 1 font-lock-constant-face)

;; Markers <<<dotprompt:role:system>>>
;; Dotprompt markers <<<dotprompt:role:system>>> etc.
'("<<<dotprompt:[^>]+>>>" . font-lock-preprocessor-face)

;; Partials {{> partialName}}
'("{{>\\s-*[a-zA-Z0-9_.-]+\\s-*\\(.*?\\)}}" . font-lock-builtin-face)
;; Handlebars block comments {{!-- ... --}}
'("{{!--\\(.\\|\n\\)*?--}}" . font-lock-comment-face)

;; Handlebars inline comments {{! ... }}
'("{{![^}]*}}" . font-lock-comment-face)

;; Partials {{> partialName}} - highlight partial indicator and name
'("{{\\(>\\)\\s-*\\([a-zA-Z0-9_.-]+\\)"
(1 font-lock-keyword-face)
(2 font-lock-builtin-face))

;; Block opening helpers {{#each items}} - highlight # + keyword AND the argument
'("{{\\(#\\)\\(if\\|unless\\|each\\|with\\|log\\|lookup\\|ifEquals\\|unlessEquals\\)\\(?:\\s-+\\([a-zA-Z0-9_.-]+\\)\\)?"
(1 font-lock-keyword-face)
(2 font-lock-keyword-face)
(3 font-lock-variable-name-face nil t))

;; Block closing helpers {{/each}} - highlight / and keyword
'("{{\\(/\\)\\(if\\|unless\\|each\\|with\\|log\\|lookup\\|ifEquals\\|unlessEquals\\)}}"
(1 font-lock-keyword-face)
(2 font-lock-keyword-face))

;; Handlebars Control Flow {{#if}} {{/if}}
'("{{[#/]\\(if\\|unless\\|each\\|with\\|log\\|lookup\\|else\\)" 1 font-lock-keyword-face)
;; Else keyword {{else}}
'("{{\\(else\\)}}" 1 font-lock-keyword-face)

;; Dotprompt Helpers (distinct color)
'("\\<\\(json\\|role\\|history\\|section\\|media\\|ifEquals\\|unlessEquals\\)\\>" . font-lock-function-name-face)
;; Dotprompt helpers {{json this indent=2}}
'("{{\\(json\\|role\\|history\\|section\\|media\\|ifEquals\\|unlessEquals\\)"
1 font-lock-function-name-face)

;; General tags
'("{{" . font-lock-delimiter-face)
'("}}" . font-lock-delimiter-face)
;; Helper named parameters (param=value)
'("\\b\\([a-zA-Z_][a-zA-Z0-9_]*\\)=" 1 font-lock-type-face)

;; Quoted strings inside handlebars
'("{{[^}]*\\([\"'][^\"']*[\"']\\)" 1 font-lock-string-face)

;; Boolean and null constants inside handlebars
'("{{[^}]*\\b\\(true\\|false\\|null\\|undefined\\)\\b" 1 font-lock-constant-face)

;; Numbers inside handlebars
'("{{[^}]*\\b\\([0-9]+\\)\\b" 1 font-lock-constant-face)

;; Simple variable references {{variableName}} or {{this}}
'("{{\\([a-zA-Z_][a-zA-Z0-9_.]*\\)}}" 1 font-lock-variable-name-face)

;; The handlebars delimiters themselves
'("\\({{\\)" 1 font-lock-constant-face)
'("\\(}}\\)" 1 font-lock-constant-face)

;; License header comments (lines starting with #)
;; This is at the END with override flag `t` to ensure entire comment lines
;; are highlighted uniformly, overriding any patterns that matched within them
'("^#.*$" 0 font-lock-comment-face t)
)
"Minimal highlighting for Dotprompt.")
"Syntax highlighting for Dotprompt templates.")

(defvar dotprompt-mode-map
(let ((map (make-sparse-keymap)))
Expand Down Expand Up @@ -132,7 +181,7 @@ Otherwise, call promptly fmt directly."
(progn
(write-region (point-min) (point-max) temp-file nil 'silent)
(let ((exit-code (call-process dotprompt-promptly-path nil nil nil
"fmt" temp-file)))
"fmt" temp-file)))
(when (zerop exit-code)
(erase-buffer)
(insert-file-contents temp-file)
Expand Down
8 changes: 4 additions & 4 deletions packages/jetbrains/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Language support for Dotprompt (`.prompt`) files in JetBrains IDEs (IntelliJ IDE
2. **Build the plugin**:
```bash
cd packages/jetbrains
./gradlew buildPlugin
gradle buildPlugin
```

3. **Install**:
Expand Down Expand Up @@ -65,13 +65,13 @@ cargo build --release -p promptly

```bash
# Build the plugin
./gradlew buildPlugin
gradle buildPlugin

# Run IDE with plugin for testing
./gradlew runIde
gradle runIde

# Run tests
./gradlew test
gradle test
```

## Live Templates
Expand Down
63 changes: 30 additions & 33 deletions packages/jetbrains/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,47 +17,44 @@
*/

plugins {
id("java")
id("org.jetbrains.kotlin.jvm") version "1.9.22"
id("org.jetbrains.intellij") version "1.17.2"
id("java")
id("org.jetbrains.kotlin.jvm") version "1.9.22"
id("org.jetbrains.intellij") version "1.17.2"
}

group = "com.google.dotprompt"

version = "0.1.0"

repositories {
mavenCentral()
}
repositories { mavenCentral() }

intellij {
version.set("2024.1")
type.set("IC") // IntelliJ IDEA Community Edition
plugins.set(listOf(
"com.redhat.devtools.lsp4ij:0.0.2" // LSP4IJ for LSP support
))
version.set("2024.1")
type.set("IC") // IntelliJ IDEA Community Edition
plugins.set(
listOf(
"com.redhat.devtools.lsp4ij:0.0.2" // LSP4IJ for LSP support
)
)
}

tasks {
withType<JavaCompile> {
sourceCompatibility = "17"
targetCompatibility = "17"
}
withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions.jvmTarget = "17"
}

patchPluginXml {
sinceBuild.set("241")
untilBuild.set("243.*")
}

signPlugin {
certificateChain.set(System.getenv("CERTIFICATE_CHAIN"))
privateKey.set(System.getenv("PRIVATE_KEY"))
password.set(System.getenv("PRIVATE_KEY_PASSWORD"))
}

publishPlugin {
token.set(System.getenv("PUBLISH_TOKEN"))
}
withType<JavaCompile> {
sourceCompatibility = "17"
targetCompatibility = "17"
}
withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> { kotlinOptions.jvmTarget = "17" }

patchPluginXml {
sinceBuild.set("241")
untilBuild.set("243.*")
}

signPlugin {
certificateChain.set(System.getenv("CERTIFICATE_CHAIN"))
privateKey.set(System.getenv("PRIVATE_KEY"))
password.set(System.getenv("PRIVATE_KEY_PASSWORD"))
}

publishPlugin { token.set(System.getenv("PUBLISH_TOKEN")) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class PromptlyServerFactory : LanguageServerFactory {
override fun createConnectionProvider(project: Project): StreamConnectionProvider {
val promptlyPath = findPromptlyExecutable()
val commands = listOf(promptlyPath, "lsp")
return ProcessStreamConnectionProvider(commands)
return object : ProcessStreamConnectionProvider(commands, project.basePath) {}
}

/**
Expand Down
5 changes: 4 additions & 1 deletion packages/vim/lua/dotprompt/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,10 @@ function M.setup(opts)
capabilities = vim.lsp.protocol.make_client_capabilities(),
})

vim.notify("Dotprompt: LSP configured with " .. promptly_path, vim.log.levels.INFO)
vim.notify(
"Dotprompt: LSP configured with " .. promptly_path,
vim.log.levels.INFO
)
end

--- Manually trigger document formatting
Expand Down
6 changes: 6 additions & 0 deletions scripts/fmt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ if command -v rust-parallel >/dev/null 2>&1; then
"${TOP_DIR}/scripts/format_handlebarrz_files" \
"${TOP_DIR}/scripts/format_toml_files" \
"${TOP_DIR}/scripts/format_ts_files" \
"${TOP_DIR}/scripts/format_kotlin_files" \
"${TOP_DIR}/scripts/format_elisp_files" \
"${TOP_DIR}/scripts/format_lua_files" \
| rust-parallel -s --exit-on-error || exit 1
else
echo "rust-parallel was not detected; not performing formatting in parallel"
Expand All @@ -48,6 +51,9 @@ else
"${TOP_DIR}/scripts/format_rust_files" || exit 1
"${TOP_DIR}/scripts/format_toml_files" || exit 1
"${TOP_DIR}/scripts/format_ts_files" || exit 1
"${TOP_DIR}/scripts/format_kotlin_files" || exit 1
"${TOP_DIR}/scripts/format_elisp_files" || exit 1
"${TOP_DIR}/scripts/format_lua_files" || exit 1
fi

# Do this after all of the above have completed.
Expand Down
43 changes: 43 additions & 0 deletions scripts/format_elisp_files
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env bash
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0

# Script to format all Elisp files in the workspace using Emacs.

set -euo pipefail

if ! command -v emacs &> /dev/null; then
echo "Emacs not found, skipping Elisp formatting."
exit 0
fi

# Find all .el files
ELISP_FILES=$(find . -type d \( -name .git -o -name .cache -o -name node_modules \) -prune -o -name "*.el" -print)

if [ -z "${ELISP_FILES}" ]; then
echo "No Elisp files found to format."
exit 0
fi

echo "=== Formatting Elisp files... ==="
for file in ${ELISP_FILES}; do
echo "Formatting ${file}..."
emacs -Q -batch "${file}" \
--eval "(defun indent-buffer () (interactive) (save-excursion (indent-region (point-min) (point-max) nil)))" \
--eval "(indent-buffer)" \
-f save-buffer
done
echo "=== Elisp formatting complete. ==="
Loading
Loading