pickls_config/config.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
use serde::Deserialize;
use std::collections::HashMap;
const DEFAULT_CTAGS_TIMEOUT_MS: u64 = 500;
#[derive(Clone, Debug, Deserialize, Default)]
pub struct PicklsConfig {
#[serde(default)]
pub languages: HashMap<String, PicklsLanguageConfig>,
pub symbols: Option<PicklsSymbolsConfig>,
#[serde(default)]
pub ai: PicklsAIConfig,
}
fn default_ctags_timeout_ms() -> u64 {
DEFAULT_CTAGS_TIMEOUT_MS
}
#[derive(Eq, PartialEq, Clone, Debug, Deserialize)]
pub struct PicklsSymbolsConfig {
pub source: PicklsSymbolsSource,
/// How long to wait for ctags to complete before timing out. Defaults to 500ms.
#[serde(default = "default_ctags_timeout_ms")]
pub ctags_timeout_ms: u64,
}
#[derive(Eq, PartialEq, Clone, Debug, Deserialize)]
pub enum PicklsSymbolsSource {
#[serde(rename = "universal-ctags")]
UniversalCtags,
}
#[derive(Clone, Debug, Default, Deserialize)]
pub struct PicklsLanguageConfig {
/// A list of pathnames that indicate the root directory in relation to a file
/// being processed. pickls will use the first directory containing one of
/// these files as the root directory. The associated linter or formatter
/// will be run with its working directory set to this directory. (ie: pyproject.toml,
/// setup.py, Cargo.toml, go.mod, Makefile, etc...)
#[serde(default)]
pub root_markers: Vec<String>,
/// All the linters you'd like to run on this language. Each linter runs in
/// a subprocess group.
#[serde(default)]
pub linters: Vec<PicklsLinterConfig>,
/// All the formatters you'd like to run (in order) on this language. Note
/// that you'll need to configure your editor to invoke its LSP client to
/// cause formatting to occur. Successive formatters that set use_stdin will
/// have chained pipes from stdout to stdin to eliminate extra copies.
#[serde(default)]
pub formatters: Vec<PicklsFormatterConfig>,
}
#[derive(Clone, Debug, Deserialize)]
pub struct PicklsLinterConfig {
/// If `program` is not an absolute path, the `PATH` will be searched in an OS-defined way.
pub program: String,
/// Arguments to pass to `program`. Use "$filename" wherever the absolute path to the real filename should go.
/// Use "$tmpfilename" where Pickls should inject a temp file (if the linter only accepts file
/// input).
#[serde(default = "Vec::new")]
pub args: Vec<String>,
/// Whether to use stdin to push the contents of the file to `program` or to rely on the usage
/// of "$filename" arg.
pub use_stdin: bool,
/// Regex from which to pull diagnostics from stdout of `program`. The pattern is matched on
/// every line of output. When there is a match, a diagnostic is produced.
pub pattern: String,
/// Regex group (1-indexed) that matches the filename of the diagnostic.
pub filename_match: Option<usize>,
/// Regex group (1-indexed) that matches the line number of the diagnostic.
pub line_match: usize,
/// Regex group (1-indexed) that matches the starting column number of the diagnostic. (Optional)
pub start_col_match: Option<usize>,
/// Regex group (1-indexed) that matches the ending column number of the diagnostic. (Optional)
pub end_col_match: Option<usize>,
/// Regex group (1-indexed) that matches the severity of the alert. Unknown severities will
/// resolve to warnings.
pub severity_match: Option<usize>,
/// Regex group (1-indexed) that matches the line number of the diagnostic. Use -1 to indicate
/// that the description is on the _previous_ line of input.
pub description_match: Option<isize>,
/// Whether to scan stderr instead of stdout. Defaults to false. Setting to true will ignore
/// stdout.
#[serde(default = "default_false")]
pub use_stderr: bool,
}
fn default_false() -> bool {
false
}
fn default_true() -> bool {
true
}
#[derive(Clone, Debug, Deserialize)]
pub struct PicklsFormatterConfig {
/// If `program` is not an absolute path, the `PATH` will be searched in an OS-defined way.
pub program: String,
/// Arguments to pass to `program`. Use "$abspath" wherever the absolute path to the filename should go.
pub args: Vec<String>,
/// Whether to use stdin to push the contents of the file to `program` or to rely on the usage
/// of "$filename" arg. Defaults to true.
#[serde(default = "default_true")]
pub use_stdin: bool,
/// If `stderr_indicates_error` is true, then if the formatter writes anything to stderr, the
/// format run will be considered a failure and aborted. Defaults to false.
#[serde(default = "default_false")]
pub stderr_indicates_error: bool,
}
#[derive(Clone, Debug, Deserialize, Default)]
pub struct PicklsAIConfig {
#[serde(default = "default_inline_assist_system_prompt")]
pub system_prompt: String,
pub inline_assist_provider: PicklsAIProvider,
#[serde(default = "default_inline_assist_prompt_template")]
pub inline_assist_prompt_template: String,
pub openai: Option<OpenAIConfig>,
pub ollama: Option<OllamaConfig>,
}
/// Ollama is a AI model driver that can be run locally.
/// See https://ollama.com/ for more information on getting it set up locally.
///
/// API docs are [here](https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-completion).
/// curl http://localhost:11434/api/generate -d '{
/// "model": "llama3.2",
/// "prompt": "Why is the sky blue?",
/// "system": "You are a good robot."
/// }'
#[derive(Clone, Debug, Deserialize, Default)]
pub struct OllamaConfig {
pub model: String,
/// Defaults to http://localhost:11434/api/generate.
pub api_address: String,
}
#[derive(Clone, Debug, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum PicklsAIProvider {
#[default]
OpenAI,
Ollama,
}
#[derive(Clone, Debug, Deserialize)]
pub struct OpenAIConfig {
/// The OpenAI model to use, (ie: "gpt-4o")
pub model: String,
/// The command to run to print the OpenAPI key. (If None, will look at $OPENAI_API_KEY)
#[serde(default = "default_openai_api_key_cmd")]
pub api_key_cmd: Vec<String>,
}
impl Default for OpenAIConfig {
fn default() -> Self {
OpenAIConfig {
model: "gpt-4o".to_string(),
api_key_cmd: default_openai_api_key_cmd(),
}
}
}
fn default_openai_api_key_cmd() -> Vec<String> {
["sh", "-c", "echo $OPENAI_API_KEY"]
.into_iter()
.map(|s| s.to_string())
.collect()
}
fn default_inline_assist_prompt_template() -> String {
"I'm working within the {{language_id}} language. If I show you code below, then please \
rewrite it to make improvements as you see fit. If I show you a question or directive, \
write code to satisfy the question or directive.\n\n\
{{text}}\n"
.to_string()
}
fn default_inline_assist_system_prompt() -> String {
"You are an inline assistant for a code editor. Your response to user prompts will be used \
to replace code in the editor."
.to_string()
}