Skip to content

Commit

Permalink
fixed various bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
cosmikwolf committed May 21, 2024
1 parent eb88018 commit 8f6ff98
Show file tree
Hide file tree
Showing 18 changed files with 279 additions and 57 deletions.
2 changes: 1 addition & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![CI](https://github.com/cosmikwolf/sazid/workflows/CI/badge.svg)](https://github.com/cosmikwolf/sazid/actions)

**Currently a work in progress**
--- embeddings are not hooked up at the moment ---
--- embeddings are currently broken---

Sazid is an interactive LLM interface written in Rust that provides:

Expand Down
3 changes: 2 additions & 1 deletion languages.toml
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,9 @@ command = [


[language-server.rust-analyzer]
# command = "ra-multiplex"
command = "rust-analyzer"
args = ["-v", "--log-file", "/tmp/rust-analyzer.log"]
# args = ["-v", "--log-file", "/tmp/rust-analyzer.log"]

[language-server.rust-analyzer.config]
inlayHints.bindingModeHints.enable = false
Expand Down
3 changes: 2 additions & 1 deletion sazid-term/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,10 @@ impl Application {
session_config.workspace = Some(WorkspaceParams {
workspace_path,
language,
language_server: "rust-analyzer".to_string(),
language_server: args.language_server.unwrap_or("rust-analyzer".to_string()),
doc_path: None,
});
log::debug!("workspace: {:#?}", session_config.workspace);
},
(None, None) => {},
(None, Some(_)) => {
Expand Down
13 changes: 9 additions & 4 deletions sazid-term/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub struct Args {
pub files: Vec<(PathBuf, Position)>,
pub workspace: Option<PathBuf>,
pub language: Option<String>,
pub language_server: Option<String>,
}

impl Args {
Expand Down Expand Up @@ -72,11 +73,15 @@ impl Args {
None => anyhow::bail!("--log must specify a path to write"),
}
},
"-l" | "--language" => match argv.next().as_deref() {
Some(language) => {
"-l" | "--language" => {
if let Some(language) = argv.next().as_deref() {
args.language = Some(language.into());
},
None => {},
}
},
"-ls" | "--language-server" => {
if let Some(language_server) = argv.next().as_deref() {
args.language_server = Some(language_server.into());
}
},
"-w" | "--workspace" => match argv.next().as_deref() {
Some(path) => {
Expand Down
11 changes: 6 additions & 5 deletions sazid-term/src/commands/llm.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{sync::Arc};
use std::sync::Arc;

use super::Context;
use crate::{
Expand Down Expand Up @@ -93,9 +93,9 @@ impl ChatMessageItem {
if self.plaintext_wrapped_width == width {
self.plain_text.len_lines()
} else {
log::error!(
"need to update wrapping before trying to get wrapped height, or else it is not up to date"
);
//log::error!(
// "need to update wrapping before trying to get wrapped height, or else it is not up to date"
//);
self.plain_text.len_lines()
}
}
Expand Down Expand Up @@ -212,7 +212,8 @@ impl ChatMessageItem {
let content =
if let ChatMessageType::Chat(ChatCompletionRequestMessage::Tool(_)) = &self.chat_message {
if self.content().lines().count() > 1 {
"tool call response content"
//"tool call response content"
self.content()
} else {
self.content()
}
Expand Down
1 change: 0 additions & 1 deletion sazid-term/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ pub enum ConfigLoadError {
BadConfig(TomlError),
Error(IOError),
}

impl Default for ConfigLoadError {
fn default() -> Self {
ConfigLoadError::Error(IOError::new(std::io::ErrorKind::NotFound, "place holder"))
Expand Down
2 changes: 1 addition & 1 deletion sazid-term/src/ui/markdown_renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ impl MarkdownRenderer {
},
// TaskListMarker(bool) true if checked
_ => {
log::warn!("unhandled markdown event {:?}", event);
//log::warn!("unhandled markdown event {:?}", event);
},
}
// build up a vec of Paragraph tui widgets
Expand Down
1 change: 1 addition & 0 deletions sazid/src/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ pub enum LsiAction {
QueryWorkspaceSymbols(LsiQuery),
GetWorkspaceFiles(LsiQuery),
ReplaceSymbolText(String, LsiQuery),
ReadSymbolSource(LsiQuery),
GoToSymbolDefinition(LsiQuery),
GoToSymbolDeclaration(LsiQuery),
GoToTypeDefinition(LsiQuery),
Expand Down
5 changes: 5 additions & 0 deletions sazid/src/app/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ pub const INGESTED_DIR: &str = ".local/share/sazid/data/ingested";

lazy_static! {
// model constants
pub static ref GPT4_O: Model = Model {
name: "gpt-4o".to_string(),
endpoint: "https://api.openai.com/v1/completions".to_string(),
token_limit: 16384,
};
pub static ref GPT4_TURBO: Model = Model {
name: "gpt-4-turbo-preview".to_string(),
endpoint: "https://api.openai.com/v1/completions".to_string(),
Expand Down
6 changes: 5 additions & 1 deletion sazid/src/app/lsi/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ impl LanguageServerInterface {
log::error!("{}", error);
Ok(None)
},
LsiAction::ReadSymbolSource(lsi_query) => {
let lsi_query_result = self.lsi_read_symbol_source(&lsi_query);
Self::handle_lsi_query_result(lsi_query, lsi_query_result)
},
LsiAction::ReplaceSymbolText(replacement_text, lsi_query) => {
let lsi_query_result = self.lsi_replace_symbol_text(replacement_text, &lsi_query);
Self::handle_lsi_query_result(lsi_query, lsi_query_result)
Expand Down Expand Up @@ -514,7 +518,7 @@ impl LanguageServerInterface {
enable_snippets,
)
.find(|(name, _client)| name == languge_server_name)
.unwrap()
.expect("language server not found")
.1
.map_err(|e| anyhow::anyhow!(e))?;
Ok(Some(client))
Expand Down
139 changes: 112 additions & 27 deletions sazid/src/app/lsi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,12 @@ fn position_gt(pos1: lsp::Position, pos2: lsp::Position) -> bool {
}

fn get_file_range_contents(file_path: &Path, range: lsp::Range) -> anyhow::Result<String> {
let source_code = std::fs::read_to_string(file_path)?;
if range.start == range.end {
return Ok(String::new());
}
let source_code = source_code
.lines()
.skip(range.start.line as usize)
.take((range.end.line - range.start.line) as usize + 1)
.enumerate()
.map(|(i, line)| {
if i == 0 {
line.chars().skip(range.start.character as usize).collect()
} else if i == (range.end.line - range.start.line) as usize {
line.chars().take(range.end.character as usize).collect()
} else {
line.to_string()
}
})
.collect::<Vec<_>>()
.join("\n");
let rope = Rope::from_reader(std::fs::File::open(file_path)?)?;

let start_char = rope.line_to_char(range.start.line as usize) + range.start.character as usize;
let end_char = rope.line_to_char(range.end.line as usize) + range.end.character as usize;

let source_code = rope.slice(start_char..end_char).to_string();
Ok(source_code)
}

Expand All @@ -50,12 +36,15 @@ pub fn replace_file_range_contents(
) -> anyhow::Result<String> {
let mut rope = Rope::from_reader(std::fs::File::open(file_path)?)?;

println!("rope: {}-", rope);
let start_char = rope.line_to_char(range.start.line as usize) + range.start.character as usize;
let end_char = rope.line_to_char(range.end.line as usize) + range.end.character as usize;

rope.remove(start_char..end_char);
let end_rope = rope.split_off(end_char);
println!("end_rope: {}-", end_rope);
rope.remove(start_char..);
rope.insert(start_char, &contents);

rope.append(end_rope);
let new_contents = rope.to_string();
std::fs::write(file_path, &new_contents)?;

Expand All @@ -65,17 +54,113 @@ pub fn replace_file_range_contents(
#[cfg(test)]
mod tests {
use super::*;
use lsp::Range;
use std::fs::read_to_string;
use std::fs::File;
use std::io::Write;
use tempfile::tempdir;

#[test]
fn test_get_file_range_contents_standard_case() -> anyhow::Result<()> {
let tmp_dir = tempdir().unwrap();
let file_path = tmp_dir.path().join("example.txt");

let mut file = File::create(&file_path)?;
write!(file, "line 1\nline 2\nline 3\nline 4")?;

let range = Range {
start: lsp_types::Position { line: 1, character: 3 },
end: lsp_types::Position { line: 2, character: 4 },
};

let content = get_file_range_contents(&file_path, range)?;
assert_eq!(content, "e 2\nline");

Ok(())
}

#[test]
fn test_get_file_range_contents_empty_range() -> anyhow::Result<()> {
let tmp_dir = tempdir().unwrap();
let file_path = tmp_dir.path().join("example.txt");

let mut file = File::create(&file_path)?;
write!(file, "line 1\nline 2\nline 3\nline 4")?;

let range = Range {
start: lsp_types::Position { line: 1, character: 3 },
end: lsp_types::Position { line: 1, character: 3 },
};

let content = get_file_range_contents(&file_path, range)?;
assert_eq!(content, "");

Ok(())
}

#[test]
fn test_get_file_range_contents_whole_file() -> anyhow::Result<()> {
let tmp_dir = tempdir().unwrap();
let file_path = tmp_dir.path().join("example.txt");

let mut file = File::create(&file_path)?;
write!(file, "line 1\nline 2\nline 3\nline 4")?;

let range = Range {
start: lsp_types::Position { line: 0, character: 0 },
end: lsp_types::Position { line: 3, character: 6 },
};

let content = get_file_range_contents(&file_path, range)?;
assert_eq!(content, "line 1\nline 2\nline 3\nline 4");

Ok(())
}

#[test]
fn test_get_file_range_contents_single_line() -> anyhow::Result<()> {
let tmp_dir = tempdir().unwrap();
let file_path = tmp_dir.path().join("example.txt");

let mut file = File::create(&file_path)?;
write!(file, "line 1\nline 2\nline 3\nline 4")?;

let range = Range {
start: lsp_types::Position { line: 1, character: 2 },
end: lsp_types::Position { line: 1, character: 5 },
};

let content = get_file_range_contents(&file_path, range)?;
assert_eq!(content, "ne 2");

Ok(())
}

#[test]
fn test_get_file_range_contents_with_special_characters() -> anyhow::Result<()> {
let tmp_dir = tempdir().unwrap();
let file_path = tmp_dir.path().join("example.txt");

let mut file = File::create(&file_path)?;
write!(file, "line 1\nlïne 2\nline 3\nlįne 4")?;

let range = Range {
start: lsp_types::Position { line: 1, character: 1 },
end: lsp_types::Position { line: 3, character: 3 },
};

let content = get_file_range_contents(&file_path, range)?;
assert_eq!(content, "ïne 2\nline 3\nlįn");

Ok(())
}
#[test]
fn test_replace_file_range_contents() {
// Create a temporary directory and file for testing
let temp_dir = tempdir().unwrap();
let file_path = temp_dir.path().join("test.txt");
let mut file = File::create(&file_path).unwrap();
writeln!(file, "line 1\nline 2\nline 3\nline 4\nline 5").unwrap();
write!(file, "line 1\nline 2\nline 3\nline 4\nline 5").unwrap();

// Test replacing content within multiple lines
let range = lsp::Range {
Expand All @@ -84,7 +169,7 @@ mod tests {
};
let contents = "new content".to_string();
let result = replace_file_range_contents(&file_path, range, contents.clone()).unwrap();
let expected_result = "line 1\nlinew content\nline 5".to_string();
let expected_result = "line 1\nlinew content3\nline 4\nline 5".to_string();
assert_eq!(result, expected_result);

// Check the contents of the file
Expand All @@ -98,7 +183,7 @@ mod tests {
};
let contents = "new".to_string();
let result = replace_file_range_contents(&file_path, range, contents).unwrap();
let expected_result = "linew 1\nline 2\nline 3\nline 4\nline 5".to_string();
let expected_result = "linew1\nlinew content3\nline 4\nline 5".to_string();
assert_eq!(result, expected_result);

// Test replacing content from the beginning of the file to the middle of a line
Expand All @@ -108,13 +193,13 @@ mod tests {
};
let contents = "start".to_string();
let result = replace_file_range_contents(&file_path, range, contents).unwrap();
let expected_result = "starte 2\nline 3\nline 4\nline 5".to_string();
let expected_result = "startew content3\nline 4\nline 5".to_string();
assert_eq!(result, expected_result);

// Test replacing the entire content of the file
let range = lsp::Range {
start: lsp::Position { line: 0, character: 0 },
end: lsp::Position { line: 4, character: 6 },
end: lsp::Position { line: 2, character: 6 },
};
let contents = "new file content".to_string();
let result = replace_file_range_contents(&file_path, range, contents).unwrap();
Expand Down
9 changes: 6 additions & 3 deletions sazid/src/app/lsi/symbol_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub struct SerializableSourceSymbol {
pub kind: lsp::SymbolKind,
pub tags: Option<Vec<lsp::SymbolTag>>,
pub range: lsp::Range,
pub selection_range: lsp::Range,
//pub selection_range: lsp::Range,
pub workspace_path: PathBuf,
pub file_path: PathBuf,
pub hash: [u8; 32],
Expand All @@ -51,7 +51,7 @@ impl From<Arc<SourceSymbol>> for SerializableSourceSymbol {
kind: symbol.kind,
tags: symbol.tags.clone(),
range: *symbol.range.lock().unwrap(),
selection_range: *symbol.selection_range.lock().unwrap(),
//selection_range: *symbol.selection_range.lock().unwrap(),
workspace_path: symbol.workspace_path.clone(),
file_path: symbol.file_path.clone(),
hash: symbol.symbol_id,
Expand Down Expand Up @@ -100,7 +100,10 @@ impl SourceSymbol {
tags: doc_sym.tags.clone(),
range: Arc::new(Mutex::new(doc_sym.range)),
selection_range: Arc::new(Mutex::new(doc_sym.selection_range)),
file_path: file_path.to_path_buf(),
file_path: file_path
.strip_prefix(workspace_path)
.expect("file is not in workspace directory")
.to_path_buf(),
parent: Arc::new(Mutex::new(Weak::new())),
children: Arc::new(Mutex::new(vec![])),
workspace_path: workspace_path.to_path_buf(),
Expand Down
Loading

0 comments on commit 8f6ff98

Please sign in to comment.