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
9 changes: 2 additions & 7 deletions .devcontainer/postCreateCommand.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
#!/usr/bin/env bash

echo "Build NPM packages"
cd client
npm update
npm run build
echo "Build server."
cd ../server
cargo build
cd server
../bt install --dev
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ jobs:
# we specify bash to get pipefail; it guards against the `curl` command
# failing. otherwise `sh` won't catch that `curl` returned non-0
shell: bash
run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.27.1/cargo-dist-installer.sh | sh"
run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.28.0/cargo-dist-installer.sh | sh"
- name: Cache dist
uses: actions/upload-artifact@v4
with:
Expand Down
69 changes: 33 additions & 36 deletions builder/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
// ## Imports
//
// ### Standard library
use std::{ffi::OsStr, fs, path::Path, process::Command};
use std::{ffi::OsStr, fs, io, path::Path, process::Command};

// ### Third-party
use clap::{Parser, Subcommand};
Expand Down Expand Up @@ -104,7 +104,7 @@ fn run_script<T: AsRef<OsStr>, P: AsRef<Path> + std::fmt::Display>(
// True to report errors based on the process' exit code; false to ignore
// the code.
check_exit_code: bool,
) -> Result<(), Box<dyn std::error::Error>> {
) -> io::Result<()> {
let mut process;
if cfg!(windows) {
process = Command::new("cmd");
Expand All @@ -120,7 +120,10 @@ fn run_script<T: AsRef<OsStr>, P: AsRef<Path> + std::fmt::Display>(
if exit_code == Some(0) || (exit_code.is_some() && !check_exit_code) {
Ok(())
} else {
Err("npm exit code indicates failure".into())
Err(io::Error::new(
io::ErrorKind::Other,
"npm exit code indicates failure.",
))
}
}

Expand All @@ -129,11 +132,7 @@ fn run_script<T: AsRef<OsStr>, P: AsRef<Path> + std::fmt::Display>(
/// programs (`robocopy`/`rsync`) to accomplish this. Very important: the `src`
/// **must** end with a `/`, otherwise the Windows and Linux copies aren't
/// identical.
fn quick_copy_dir<P: AsRef<OsStr>>(
src: P,
dest: P,
files: Option<P>,
) -> Result<(), Box<dyn std::error::Error>> {
fn quick_copy_dir<P: AsRef<OsStr>>(src: P, dest: P, files: Option<P>) -> io::Result<()> {
assert!(src.as_ref().to_string_lossy().ends_with('/'));
let mut copy_process;
#[cfg(windows)]
Expand Down Expand Up @@ -206,29 +205,26 @@ fn quick_copy_dir<P: AsRef<OsStr>>(
println!("{:#?}", &copy_process);

// Check for errors.
let exit_status = copy_process
.status()
.map_err(|err| -> String { format!("Error running copy process: {err}") })?;
let exit_code = exit_status
let exit_code = copy_process
.status()?
.code()
.expect("Copy process terminated by signal");
// Per
// [these docs](https://learn.microsoft.com/en-us/troubleshoot/windows-server/backup-and-storage/return-codes-used-robocopy-utility),
// check the return code.
if cfg!(windows) && exit_code >= 8 || !cfg!(windows) && exit_code != 0 {
Err(format!("Copy process return code {exit_code} indicates failure.").into())
Err(io::Error::new(
io::ErrorKind::Other,
format!("Copy process return code {exit_code} indicates failure."),
))
} else {
Ok(())
}
}

fn remove_dir_all_if_exists<P: AsRef<Path> + std::fmt::Display>(
path: P,
) -> Result<(), Box<dyn std::error::Error>> {
fn remove_dir_all_if_exists<P: AsRef<Path> + std::fmt::Display>(path: P) -> io::Result<()> {
if Path::new(path.as_ref()).try_exists().unwrap() {
if let Err(err) = fs::remove_dir_all(path.as_ref()) {
return Err(format!("Error removing directory tree {path}: {err}").into());
}
fs::remove_dir_all(path.as_ref())?;
}

Ok(())
Expand All @@ -242,27 +238,28 @@ fn search_and_replace_file<
path: P,
search_regex: S1,
replace_string: S2,
) -> Result<(), Box<dyn std::error::Error>> {
let file_contents = fs::read_to_string(&path)
.map_err(|err| -> String { format!("Unable to open file {path} for reading: {err}") })?;
let re = Regex::new(search_regex.as_ref())
.map_err(|err| -> String { format!("Error in search regex {search_regex}: {err}") })?;
) -> io::Result<()> {
let file_contents = fs::read_to_string(&path)?;
let re = Regex::new(search_regex.as_ref()).map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!("Error in search regex {search_regex}: {err}"),
)
})?;
let file_contents_replaced = re.replace(&file_contents, replace_string.as_ref());
assert_ne!(
file_contents, file_contents_replaced,
"No replacements made."
);
fs::write(&path, file_contents_replaced.as_bytes())
.map_err(|err| -> String { format!("Error writing to {path}: {err}") })?;
Ok(())
}

// ## Core routines
//
// These functions simplify common build-focused development tasks and support
// CI builds.
/// After updating files in the client's Node files, perform some fix-ups.
fn patch_client_npm() -> Result<(), Box<dyn std::error::Error>> {
fn patch_client_npm() -> io::Result<()> {
// Apply a the fixes described in
// [issue 27](https://github.com/bjones1/CodeChat_Editor/issues/27).
//
Expand Down Expand Up @@ -310,7 +307,7 @@ fn patch_client_npm() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}

fn run_install(dev: bool) -> Result<(), Box<dyn std::error::Error>> {
fn run_install(dev: bool) -> io::Result<()> {
run_script("npm", &["install"], "../client", true)?;
patch_client_npm()?;
run_script("npm", &["install"], "../extensions/VSCode", true)?;
Expand All @@ -331,7 +328,7 @@ fn run_install(dev: bool) -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}

fn run_update() -> Result<(), Box<dyn std::error::Error>> {
fn run_update() -> io::Result<()> {
run_script("npm", &["update"], "../client", true)?;
patch_client_npm()?;
run_script("npm", &["update"], "../extensions/VSCode", true)?;
Expand All @@ -349,7 +346,7 @@ fn run_update() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}

fn run_test() -> Result<(), Box<dyn std::error::Error>> {
fn run_test() -> io::Result<()> {
// On Windows, `cargo sort --check` fails since it default to LF, not CRLF,
// line endings. Work around this by changing this setting only on Windows.
// See the
Expand Down Expand Up @@ -392,7 +389,7 @@ fn run_test() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}

fn run_build() -> Result<(), Box<dyn std::error::Error>> {
fn run_build() -> io::Result<()> {
// Clean out all bundled files before the rebuild.
remove_dir_all_if_exists("../client/static/bundled")?;
run_script("npm", &["run", "build"], "../client", true)?;
Expand All @@ -404,7 +401,7 @@ fn run_build() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}

fn run_change_version(new_version: &String) -> Result<(), Box<dyn std::error::Error>> {
fn run_change_version(new_version: &String) -> io::Result<()> {
let replacement_string = format!("${{1}}{new_version}${{2}}");
search_and_replace_file(
"Cargo.toml",
Expand All @@ -425,15 +422,15 @@ fn run_change_version(new_version: &String) -> Result<(), Box<dyn std::error::Er
Ok(())
}

fn run_prerelease() -> Result<(), Box<dyn std::error::Error>> {
fn run_prerelease() -> io::Result<()> {
// Clean out all bundled files before the rebuild.
remove_dir_all_if_exists("../client/static/bundled")?;
run_install(true)?;
run_script("npm", &["run", "dist"], "../client", true)?;
Ok(())
}

fn run_postrelease(target: &str) -> Result<(), Box<dyn std::error::Error>> {
fn run_postrelease(target: &str) -> io::Result<()> {
let server_dir = "../extensions/VSCode/server";
// Only clean the `server/` directory if it exists.
remove_dir_all_if_exists(server_dir)?;
Expand Down Expand Up @@ -468,7 +465,7 @@ fn run_postrelease(target: &str) -> Result<(), Box<dyn std::error::Error>> {
// The following code implements the command-line interface for the CodeChat
// Editor.
impl Cli {
fn run(self) -> Result<(), Box<dyn std::error::Error>> {
fn run(self) -> io::Result<()> {
match &self.command {
Commands::Install { dev } => run_install(*dev),
Commands::Update => run_update(),
Expand All @@ -481,7 +478,7 @@ impl Cli {
}
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
fn main() -> io::Result<()> {
let cli = Cli::parse();
cli.run()?;

Expand Down
3 changes: 2 additions & 1 deletion docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ CodeChat Editor. If not, see
# Changelog

- [Github master](https://github.com/bjones1/CodeChat_Editor):
- No changes.
- Correctly handle file not found in VSCode.
- Correct filename handling on Windows.
- v0.1.7, 2025-Jan-08:
- Fixed hyperlink navigation.
- Fixed case-insensitive filename handling bugs.
Expand Down
33 changes: 18 additions & 15 deletions extensions/VSCode/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@
//
// # `extension.ts` - The CodeChat Editor Visual Studio Code extension
//
// This extension creates a webview (see `activation/deactivation`\_), then uses
// a websocket connection to the CodeChat Editor Server and Client to render
// editor text in that webview.
// This extension creates a webview, then uses a websocket connection to the
// CodeChat Editor Server and Client to render editor text in that webview.
//
// ## Imports
//
Expand Down Expand Up @@ -237,7 +236,8 @@ export const activate = (context: vscode.ExtensionContext) => {
// column.
viewColumn: vscode.ViewColumn.Beside,
},
// See WebViewOptions\_.
// See
// [WebViewOptions](https://code.visualstudio.com/api/references/vscode-api#WebviewOptions).
{
enableScripts: true,
// Per the
Expand All @@ -257,9 +257,6 @@ export const activate = (context: vscode.ExtensionContext) => {
retainContextWhenHidden: true,
}
);
// TODO: do I need to dispose of this and the following
// event handlers? I'm assuming that it will be done
// automatically when the object is disposed.
webview_panel.onDidDispose(async () => {
// Shut down the render client when the webview
// panel closes.
Expand Down Expand Up @@ -436,14 +433,20 @@ export const activate = (context: vscode.ExtensionContext) => {
const current_file = value as string;
vscode.workspace
.openTextDocument(current_file)
.then((document) => {
ignore_active_editor_change = true;
vscode.window.showTextDocument(
document,
current_editor?.viewColumn
);
send_result(id);
});
.then(
(document) => {
ignore_active_editor_change = true;
vscode.window.showTextDocument(
document,
current_editor?.viewColumn
);
send_result(id);
},
(reason) =>
send_result(id, {
Err: `Error: unable to open file ${current_file}: ${reason}`,
})
);
break;
}

Expand Down
2 changes: 1 addition & 1 deletion server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ mime = "0.3.17"
mime_guess = "2.0.5"
minreq = "2.12.0"
normalize-line-endings = "0.3.0"
notify-debouncer-full = "0.4"
notify-debouncer-full = "0.5"
open = "5.3.0"
path-slash = "0.2.1"
pest = "2.7.14"
Expand Down
2 changes: 1 addition & 1 deletion server/dist-workspace.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ members = ["cargo:."]
# Config for 'dist'
[dist]
# The preferred dist version to use in CI (Cargo.toml SemVer syntax)
cargo-dist-version = "0.27.1"
cargo-dist-version = "0.28.0"
# Extra static files to include in each App (path relative to this Cargo.toml's dir)
include = ["log4rs.yml", "hashLocations.json", "../client/static"]
# The installers to generate for each app
Expand Down
3 changes: 2 additions & 1 deletion server/src/processing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,12 @@ pub fn find_path_to_toc(file_path: &Path) -> Option<PathBuf> {
// named `toc.md`.
let mut path_to_toc = PathBuf::new();
let mut current_dir = file_path.to_path_buf();
// Drop the last element (the current file name) from the search.
current_dir.pop();
loop {
let mut project_file = current_dir.clone();
project_file.push("toc.md");
if project_file.is_file() {
path_to_toc.pop();
path_to_toc.push("toc.md");
return Some(path_to_toc);
}
Expand Down
Loading
Loading