docs: Add Rustdoc comments for various structs and functions
Co-authored-by: aider (openai/andrew/openrouter/sonoma-sky-alpha) <aider@aider.chat>
This commit is contained in:
@@ -4,7 +4,15 @@ use serde::{Deserialize, Serialize};
|
||||
use serde_yaml;
|
||||
use crate::meta_plugin::MetaPlugin;
|
||||
|
||||
/// Mode for generating a default configuration file.
|
||||
///
|
||||
/// This module creates a commented YAML template with default values for settings,
|
||||
/// including list format, server config, compression, and meta plugins.
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
/// Default configuration structure for the generated template.
|
||||
///
|
||||
/// Includes core settings, list formatting, server options, compression, and meta plugins.
|
||||
struct DefaultConfig {
|
||||
dir: Option<String>,
|
||||
list_format: Vec<ColumnConfig>,
|
||||
@@ -18,6 +26,7 @@ struct DefaultConfig {
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
/// Configuration for a column in the list format.
|
||||
struct ColumnConfig {
|
||||
name: String,
|
||||
label: Option<String>,
|
||||
@@ -29,6 +38,7 @@ struct ColumnConfig {
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
/// Alignment options for table columns.
|
||||
enum ColumnAlignment {
|
||||
#[default]
|
||||
Left,
|
||||
@@ -36,6 +46,7 @@ enum ColumnAlignment {
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
/// Server configuration options.
|
||||
struct ServerConfig {
|
||||
address: Option<String>,
|
||||
port: Option<u16>,
|
||||
@@ -45,11 +56,13 @@ struct ServerConfig {
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
/// Configuration for the compression plugin.
|
||||
struct CompressionPluginConfig {
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
/// Configuration for a meta plugin.
|
||||
struct MetaPluginConfig {
|
||||
name: String,
|
||||
#[serde(default)]
|
||||
@@ -58,126 +71,155 @@ struct MetaPluginConfig {
|
||||
outputs: std::collections::HashMap<String, String>,
|
||||
}
|
||||
|
||||
pub fn mode_generate_config(_cmd: &mut Command, _settings: &crate::config::Settings) -> Result<()> {
|
||||
// Create instances of each meta plugin to get their default options and outputs
|
||||
let text_plugin = crate::meta_plugin::text::TextMetaPlugin::new(None, None);
|
||||
let cwd_plugin = crate::meta_plugin::cwd::CwdMetaPlugin::new(None, None);
|
||||
let digest_plugin = crate::meta_plugin::digest::DigestMetaPlugin::new(None, None);
|
||||
let hostname_plugin = crate::meta_plugin::hostname::HostnameMetaPlugin::new(None, None);
|
||||
#[cfg(feature = "magic")]
|
||||
let magic_file_plugin = crate::meta_plugin::magic_file::MagicFileMetaPlugin::new(None, None);
|
||||
let env_plugin = crate::meta_plugin::env::EnvMetaPlugin::new(None, None);
|
||||
|
||||
// Create a default configuration
|
||||
let default_config = DefaultConfig {
|
||||
dir: Some("~/.local/share/keep".to_string()),
|
||||
list_format: vec![
|
||||
ColumnConfig {
|
||||
name: "id".to_string(),
|
||||
label: Some("Item".to_string()),
|
||||
align: ColumnAlignment::Right,
|
||||
max_len: None,
|
||||
},
|
||||
ColumnConfig {
|
||||
name: "time".to_string(),
|
||||
label: Some("Time".to_string()),
|
||||
align: ColumnAlignment::Right,
|
||||
max_len: None,
|
||||
},
|
||||
ColumnConfig {
|
||||
name: "size".to_string(),
|
||||
label: Some("Size".to_string()),
|
||||
align: ColumnAlignment::Right,
|
||||
max_len: None,
|
||||
},
|
||||
ColumnConfig {
|
||||
name: "meta:text_line_count".to_string(),
|
||||
label: Some("Lines".to_string()),
|
||||
align: ColumnAlignment::Right,
|
||||
max_len: None,
|
||||
},
|
||||
ColumnConfig {
|
||||
name: "tags".to_string(),
|
||||
label: Some("Tags".to_string()),
|
||||
align: ColumnAlignment::Left,
|
||||
max_len: Some("40".to_string()),
|
||||
},
|
||||
ColumnConfig {
|
||||
name: "meta:hostname_full".to_string(),
|
||||
label: Some("Hostname".to_string()),
|
||||
align: ColumnAlignment::Left,
|
||||
max_len: Some("28".to_string()),
|
||||
},
|
||||
],
|
||||
human_readable: false,
|
||||
output_format: Some("table".to_string()),
|
||||
quiet: false,
|
||||
force: false,
|
||||
server: Some(ServerConfig {
|
||||
address: Some("127.0.0.1".to_string()),
|
||||
port: Some(8080),
|
||||
password_file: None,
|
||||
password: None,
|
||||
password_hash: None,
|
||||
}),
|
||||
compression_plugin: None,
|
||||
meta_plugins: Some(vec![
|
||||
MetaPluginConfig {
|
||||
name: "text".to_string(),
|
||||
options: text_plugin.options().clone(),
|
||||
outputs: convert_outputs_to_string_map(text_plugin.outputs()),
|
||||
},
|
||||
MetaPluginConfig {
|
||||
name: "cwd".to_string(),
|
||||
options: cwd_plugin.options().clone(),
|
||||
outputs: convert_outputs_to_string_map(cwd_plugin.outputs()),
|
||||
},
|
||||
MetaPluginConfig {
|
||||
name: "digest".to_string(),
|
||||
options: digest_plugin.options().clone(),
|
||||
outputs: convert_outputs_to_string_map(digest_plugin.outputs()),
|
||||
},
|
||||
MetaPluginConfig {
|
||||
name: "hostname".to_string(),
|
||||
options: hostname_plugin.options().clone(),
|
||||
outputs: convert_outputs_to_string_map(hostname_plugin.outputs()),
|
||||
},
|
||||
#[cfg(feature = "magic")]
|
||||
MetaPluginConfig {
|
||||
name: "magic_file".to_string(),
|
||||
options: magic_file_plugin.options().clone(),
|
||||
outputs: convert_outputs_to_string_map(magic_file_plugin.outputs()),
|
||||
},
|
||||
MetaPluginConfig {
|
||||
name: "env".to_string(),
|
||||
options: env_plugin.options().clone(),
|
||||
outputs: convert_outputs_to_string_map(env_plugin.outputs()),
|
||||
},
|
||||
]),
|
||||
};
|
||||
|
||||
// Serialize to YAML and comment out all lines
|
||||
let yaml = serde_yaml::to_string(&default_config)?;
|
||||
|
||||
// Comment out every line
|
||||
let commented_yaml = yaml
|
||||
.lines()
|
||||
.map(|line| {
|
||||
if line.trim().is_empty() {
|
||||
line.to_string()
|
||||
} else {
|
||||
format!("# {}", line)
|
||||
}
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n");
|
||||
|
||||
println!("{}", commented_yaml);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
/// Generates and prints a default commented YAML configuration template.
|
||||
///
|
||||
/// Creates instances of available meta plugins to populate default options and outputs,
|
||||
/// then serializes the config to YAML with all lines commented for easy editing.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `_cmd` - Unused Clap command reference.
|
||||
/// * `_settings` - Unused settings reference.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// `Ok(())` on success.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// mode_generate_config(&mut cmd, &settings)?;
|
||||
/// ```
|
||||
pub fn mode_generate_config(_cmd: &mut Command, _settings: &crate::config::Settings) -> Result<()> {
|
||||
// Create instances of each meta plugin to get their default options and outputs
|
||||
let text_plugin = crate::meta_plugin::text::TextMetaPlugin::new(None, None);
|
||||
let cwd_plugin = crate::meta_plugin::cwd::CwdMetaPlugin::new(None, None);
|
||||
let digest_plugin = crate::meta_plugin::digest::DigestMetaPlugin::new(None, None);
|
||||
let hostname_plugin = crate::meta_plugin::hostname::HostnameMetaPlugin::new(None, None);
|
||||
#[cfg(feature = "magic")]
|
||||
let magic_file_plugin = crate::meta_plugin::magic_file::MagicFileMetaPlugin::new(None, None);
|
||||
let env_plugin = crate::meta_plugin::env::EnvMetaPlugin::new(None, None);
|
||||
|
||||
// Create a default configuration
|
||||
let default_config = DefaultConfig {
|
||||
dir: Some("~/.local/share/keep".to_string()),
|
||||
list_format: vec![
|
||||
ColumnConfig {
|
||||
name: "id".to_string(),
|
||||
label: Some("Item".to_string()),
|
||||
align: ColumnAlignment::Right,
|
||||
max_len: None,
|
||||
},
|
||||
ColumnConfig {
|
||||
name: "time".to_string(),
|
||||
label: Some("Time".to_string()),
|
||||
align: ColumnAlignment::Right,
|
||||
max_len: None,
|
||||
},
|
||||
ColumnConfig {
|
||||
name: "size".to_string(),
|
||||
label: Some("Size".to_string()),
|
||||
align: ColumnAlignment::Right,
|
||||
max_len: None,
|
||||
},
|
||||
ColumnConfig {
|
||||
name: "meta:text_line_count".to_string(),
|
||||
label: Some("Lines".to_string()),
|
||||
align: ColumnAlignment::Right,
|
||||
max_len: None,
|
||||
},
|
||||
ColumnConfig {
|
||||
name: "tags".to_string(),
|
||||
label: Some("Tags".to_string()),
|
||||
align: ColumnAlignment::Left,
|
||||
max_len: Some("40".to_string()),
|
||||
},
|
||||
ColumnConfig {
|
||||
name: "meta:hostname_full".to_string(),
|
||||
label: Some("Hostname".to_string()),
|
||||
align: ColumnAlignment::Left,
|
||||
max_len: Some("28".to_string()),
|
||||
},
|
||||
],
|
||||
human_readable: false,
|
||||
output_format: Some("table".to_string()),
|
||||
quiet: false,
|
||||
force: false,
|
||||
server: Some(ServerConfig {
|
||||
address: Some("127.0.0.1".to_string()),
|
||||
port: Some(8080),
|
||||
password_file: None,
|
||||
password: None,
|
||||
password_hash: None,
|
||||
}),
|
||||
compression_plugin: None,
|
||||
meta_plugins: Some(vec![
|
||||
MetaPluginConfig {
|
||||
name: "text".to_string(),
|
||||
options: text_plugin.options().clone(),
|
||||
outputs: convert_outputs_to_string_map(text_plugin.outputs()),
|
||||
},
|
||||
MetaPluginConfig {
|
||||
name: "cwd".to_string(),
|
||||
options: cwd_plugin.options().clone(),
|
||||
outputs: convert_outputs_to_string_map(cwd_plugin.outputs()),
|
||||
},
|
||||
MetaPluginConfig {
|
||||
name: "digest".to_string(),
|
||||
options: digest_plugin.options().clone(),
|
||||
outputs: convert_outputs_to_string_map(digest_plugin.outputs()),
|
||||
},
|
||||
MetaPluginConfig {
|
||||
name: "hostname".to_string(),
|
||||
options: hostname_plugin.options().clone(),
|
||||
outputs: convert_outputs_to_string_map(hostname_plugin.outputs()),
|
||||
},
|
||||
#[cfg(feature = "magic")]
|
||||
MetaPluginConfig {
|
||||
name: "magic_file".to_string(),
|
||||
options: magic_file_plugin.options().clone(),
|
||||
outputs: convert_outputs_to_string_map(magic_file_plugin.outputs()),
|
||||
},
|
||||
MetaPluginConfig {
|
||||
name: "env".to_string(),
|
||||
options: env_plugin.options().clone(),
|
||||
outputs: convert_outputs_to_string_map(env_plugin.outputs()),
|
||||
},
|
||||
]),
|
||||
};
|
||||
|
||||
// Serialize to YAML and comment out all lines
|
||||
let yaml = serde_yaml::to_string(&default_config)?;
|
||||
|
||||
// Comment out every line
|
||||
let commented_yaml = yaml
|
||||
.lines()
|
||||
.map(|line| {
|
||||
if line.trim().is_empty() {
|
||||
line.to_string()
|
||||
} else {
|
||||
format!("# {}", line)
|
||||
}
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n");
|
||||
|
||||
println!("{}", commented_yaml);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Helper function to convert outputs from serde_yaml::Value to String
|
||||
/// Helper function to convert outputs from serde_yaml::Value to String.
|
||||
///
|
||||
/// Handles null (uses key), strings, and other values by serializing to YAML string.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `outputs` - Reference to the outputs HashMap.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A HashMap with string keys and values.
|
||||
fn convert_outputs_to_string_map(
|
||||
outputs: &std::collections::HashMap<String, serde_yaml::Value>,
|
||||
) -> std::collections::HashMap<String, String> {
|
||||
|
||||
@@ -3,6 +3,10 @@ pub mod tools;
|
||||
|
||||
pub use server::KeepMcpServer;
|
||||
|
||||
/// Module for handling MCP (Model Context Protocol) requests in the server.
|
||||
///
|
||||
/// Provides handlers for JSON-RPC style requests to interact with Keep's storage
|
||||
/// via the API.
|
||||
use axum::{
|
||||
extract::State,
|
||||
http::StatusCode,
|
||||
@@ -15,46 +19,69 @@ use serde_json::Value;
|
||||
use crate::modes::server::common::AppState;
|
||||
use crate::modes::server::common::ApiResponse;
|
||||
|
||||
/// Request structure for MCP JSON-RPC calls.
|
||||
///
|
||||
/// # Fields
|
||||
///
|
||||
/// * `method` - The MCP method name (e.g., "save_item").
|
||||
/// * `params` - Optional JSON parameters for the method.
|
||||
#[derive(Deserialize)]
|
||||
pub struct McpRequest {
|
||||
pub method: String,
|
||||
pub params: Option<Value>,
|
||||
}
|
||||
|
||||
pub async fn handle_mcp_request(
|
||||
State(state): State<AppState>,
|
||||
Json(request): Json<McpRequest>,
|
||||
) -> impl IntoResponse {
|
||||
let mcp_server = KeepMcpServer::new(state);
|
||||
|
||||
match mcp_server.handle_request(&request.method, request.params).await {
|
||||
Ok(result) => {
|
||||
match serde_json::from_str(&result) {
|
||||
Ok(parsed_result) => {
|
||||
let response = ApiResponse {
|
||||
success: true,
|
||||
data: Some(parsed_result),
|
||||
error: None,
|
||||
};
|
||||
(StatusCode::OK, Json(response))
|
||||
}
|
||||
Err(_) => {
|
||||
let response = ApiResponse {
|
||||
success: true,
|
||||
data: Some(serde_json::Value::String(result)),
|
||||
error: None,
|
||||
};
|
||||
(StatusCode::OK, Json(response))
|
||||
/// Handles an MCP request via the Axum framework.
|
||||
///
|
||||
/// Parses the JSON request, delegates to `KeepMcpServer`, and returns an API response.
|
||||
/// Attempts to parse the result as JSON; falls back to string if invalid.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `State(state)` - The application state.
|
||||
/// * `Json(request)` - The deserialized MCP request.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// An `IntoResponse` with status code and JSON API response.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns 400 Bad Request on handler errors.
|
||||
pub async fn handle_mcp_request(
|
||||
State(state): State<AppState>,
|
||||
Json(request): Json<McpRequest>,
|
||||
) -> impl IntoResponse {
|
||||
let mcp_server = KeepMcpServer::new(state);
|
||||
|
||||
match mcp_server.handle_request(&request.method, request.params).await {
|
||||
Ok(result) => {
|
||||
match serde_json::from_str(&result) {
|
||||
Ok(parsed_result) => {
|
||||
let response = ApiResponse {
|
||||
success: true,
|
||||
data: Some(parsed_result),
|
||||
error: None,
|
||||
};
|
||||
(StatusCode::OK, Json(response))
|
||||
}
|
||||
Err(_) => {
|
||||
let response = ApiResponse {
|
||||
success: true,
|
||||
data: Some(serde_json::Value::String(result)),
|
||||
error: None,
|
||||
};
|
||||
(StatusCode::OK, Json(response))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
let response = ApiResponse {
|
||||
success: false,
|
||||
data: None,
|
||||
error: Some(e.to_string()),
|
||||
};
|
||||
(StatusCode::BAD_REQUEST, Json(response))
|
||||
Err(e) => {
|
||||
let response = ApiResponse {
|
||||
success: false,
|
||||
data: None,
|
||||
error: Some(e.to_string()),
|
||||
};
|
||||
(StatusCode::BAD_REQUEST, Json(response))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user