mirror of
https://github.com/joshuadavidthomas/django-language-server.git
synced 2025-09-12 13:26:51 +00:00
implement basic config
This commit is contained in:
parent
134f3fea54
commit
62ec21584b
3 changed files with 112 additions and 3 deletions
|
@ -9,10 +9,14 @@ djls-ipc = { workspace = true }
|
||||||
djls-server = { workspace = true }
|
djls-server = { workspace = true }
|
||||||
|
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
|
serde = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
|
thiserror = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
|
|
||||||
clap = { version = "4.5.23", features = ["derive"] }
|
clap = { version = "4.5.23", features = ["derive", "env"] }
|
||||||
|
dirs = "5.0.1"
|
||||||
|
figment = { version = "0.10.19", features = ["env", "toml"] }
|
||||||
tower-lsp = { version = "0.20.0", features = ["proposed"] }
|
tower-lsp = { version = "0.20.0", features = ["proposed"] }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
|
94
crates/djlc-cli/src/config.rs
Normal file
94
crates/djlc-cli/src/config.rs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
use clap::Args;
|
||||||
|
use figment::providers::{Env, Format, Serialized, Toml};
|
||||||
|
use figment::Figment;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
const CONFIG_FILES: [&str; 3] = [
|
||||||
|
"djls.toml", // highest priority
|
||||||
|
".djls.toml",
|
||||||
|
"pyproject.toml", // lowest priority
|
||||||
|
];
|
||||||
|
|
||||||
|
#[derive(Args, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct Config {
|
||||||
|
/// Override the virtual environment path
|
||||||
|
#[arg(long, env = "DJLS_VENV_PATH")]
|
||||||
|
pub venv_path: Option<PathBuf>,
|
||||||
|
|
||||||
|
/// Django settings module
|
||||||
|
#[arg(long, env = "DJANGO_SETTINGS_MODULE")]
|
||||||
|
pub django_settings_module: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Config {
|
||||||
|
fn default() -> Self {
|
||||||
|
Config {
|
||||||
|
venv_path: std::env::var("VIRTUAL_ENV").ok().map(PathBuf::from),
|
||||||
|
django_settings_module: std::env::var("DJANGO_SETTINGS_MODULE").unwrap_or_default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
fn validate(self) -> Result<Self, ConfigError> {
|
||||||
|
if self.django_settings_module.is_empty() {
|
||||||
|
return Err(ConfigError::MissingDjangoSettings);
|
||||||
|
}
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_config_up_tree(start_dir: &Path) -> Vec<PathBuf> {
|
||||||
|
let mut configs = Vec::new();
|
||||||
|
let mut current_dir = start_dir.to_path_buf();
|
||||||
|
|
||||||
|
while let Some(parent) = current_dir.parent() {
|
||||||
|
for &config_name in CONFIG_FILES.iter() {
|
||||||
|
let config_path = current_dir.join(config_name);
|
||||||
|
if config_path.exists() {
|
||||||
|
configs.push(config_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current_dir = parent.to_path_buf();
|
||||||
|
}
|
||||||
|
|
||||||
|
configs
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_config(cli_config: &Config) -> Result<Config, ConfigError> {
|
||||||
|
let platform_config = dirs::config_dir()
|
||||||
|
.map(|dir| dir.join("djls/config.toml"))
|
||||||
|
.filter(|p| p.exists());
|
||||||
|
|
||||||
|
let mut figment = Figment::new()
|
||||||
|
.merge(Serialized::defaults(Config::default()))
|
||||||
|
.merge(
|
||||||
|
platform_config
|
||||||
|
.map(|p| Toml::file(&p))
|
||||||
|
.unwrap_or_else(|| Toml::file("/dev/null")),
|
||||||
|
);
|
||||||
|
|
||||||
|
let current_dir = std::env::current_dir().map_err(ConfigError::CurrentDir)?;
|
||||||
|
for path in find_config_up_tree(¤t_dir) {
|
||||||
|
figment = figment.merge(Toml::file(&path));
|
||||||
|
}
|
||||||
|
|
||||||
|
let config: Config = figment
|
||||||
|
.merge(Env::raw().only(&["DJANGO_SETTINGS_MODULE"]))
|
||||||
|
.merge(Env::prefixed("DJLS_").split("_"))
|
||||||
|
.merge(Serialized::defaults(cli_config))
|
||||||
|
.extract()?;
|
||||||
|
|
||||||
|
config.validate()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum ConfigError {
|
||||||
|
#[error("Django settings module not specified")]
|
||||||
|
MissingDjangoSettings,
|
||||||
|
#[error("could not determine current directory: {0}")]
|
||||||
|
CurrentDir(std::io::Error),
|
||||||
|
#[error("figment error: {0}")]
|
||||||
|
Figment(#[from] figment::Error),
|
||||||
|
}
|
|
@ -1,6 +1,9 @@
|
||||||
|
mod config;
|
||||||
|
|
||||||
|
use crate::config::{load_config, Config};
|
||||||
|
use anyhow::Context;
|
||||||
use clap::{Args, Parser, Subcommand};
|
use clap::{Args, Parser, Subcommand};
|
||||||
use djls_ipc::v1::*;
|
use djls_ipc::PythonProcess;
|
||||||
use djls_ipc::{ProcessError, PythonProcess, TransportError};
|
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
@ -8,6 +11,9 @@ use std::time::Duration;
|
||||||
struct Cli {
|
struct Cli {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
command: Commands,
|
command: Commands,
|
||||||
|
|
||||||
|
#[command(flatten)]
|
||||||
|
config: Config,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Args)]
|
#[derive(Debug, Args)]
|
||||||
|
@ -40,16 +46,21 @@ enum Commands {
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
|
let config = load_config(&cli.config).context("failed to load configuration")?;
|
||||||
|
|
||||||
match cli.command {
|
match cli.command {
|
||||||
Commands::Serve(opts) => {
|
Commands::Serve(opts) => {
|
||||||
println!("Starting LSP server...");
|
println!("Starting LSP server...");
|
||||||
|
println!("With config: {:?}", config);
|
||||||
|
|
||||||
let python = PythonProcess::new::<Vec<&OsStr>, &OsStr>(
|
let python = PythonProcess::new::<Vec<&OsStr>, &OsStr>(
|
||||||
"djls.agent",
|
"djls.agent",
|
||||||
None,
|
None,
|
||||||
opts.health_check_interval(),
|
opts.health_check_interval(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
println!("LSP server started, beginning to serve...");
|
println!("LSP server started, beginning to serve...");
|
||||||
|
|
||||||
djls_server::serve(python).await?
|
djls_server::serve(python).await?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue