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
28 changes: 23 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,30 @@ Or pick a tarball manually from [GitHub Releases](https://github.com/gi-dellav/z

### Nix

```bash
# Run directly
nix run github:gi-dellav/zerostack
Run directly with [`nix-run`](https://tangled.org/weethet.eurosky.social/nix-run/):

```console
$ nix-run https://github.com/gi-dellav/zerostack/archive/refs/heads/main.tar.gz
```

Add to profile:

```console
$ nix profile add --file https://github.com/gi-dellav/zerostack/archive/refs/heads/main.tar.gz
```

# Install into your profile
nix profile install github:gi-dellav/zerostack
Add as an overlay to your system/project:

```nix
let
pkgs = import nixpkgs {
overlays = [
# src thru input pinning mechanism, or use builtins.fetchTarball
(import "${zerostack-src}/nix/overlay")
];
};
in
pkgs.zerostack
```

### Cargo
Expand Down
1 change: 1 addition & 0 deletions default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(import ./release.nix { }).default
56 changes: 0 additions & 56 deletions flake.nix

This file was deleted.

3 changes: 3 additions & 0 deletions nix/overlay/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
final: prev: {
zerostack = final.callPackage ../package/zerostack.nix { };
}
3 changes: 3 additions & 0 deletions nix/overlay/development.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
final: prev: {
zerostack-dev-shell = final.callPackage ../package/dev-shell.nix { };
}
16 changes: 16 additions & 0 deletions nix/package/dev-shell.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{ mkShell
, clippy
, rust-analyzer
, rustfmt
, zerostack
}:

mkShell {
inputsFrom = [ zerostack ];

buildInputs = [
clippy
rust-analyzer
rustfmt
];
}
49 changes: 49 additions & 0 deletions nix/package/zerostack.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{ lib
, rustPlatform
, binutils
, mold
, openssl
, pkg-config
}:

let
manifest = (lib.importTOML ../../Cargo.toml).package;
in
rustPlatform.buildRustPackage {
pname = manifest.name;
version = manifest.version;

# TODO: upgrade to lib.fileset as cleanSource is including many irrelevent
# files for the build (many *.md files, .git* files, & so on).
src = lib.cleanSource ../..;

cargoLock.lockFile = ../../Cargo.lock;

nativeBuildInputs = [
binutils
mold
pkg-config
];

buildInputs = [
openssl
];

buildFeatures = [
"acp"
"memory"
"multithread"
];

# TODO: there needs to be a list of tests that can vs. can’t run in the Nix
# sandbox
doCheck = false;

meta = {
description = manifest.description;
license = lib.licenses.gpl3Only;
homepage = manifest.homepage;
mainProgram = "zerostack";
platforms = with lib.platforms; linux ++ darwin;
};
}
21 changes: 21 additions & 0 deletions release.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
system ? builtins.currentSystem,
nixpkgs ? <nixpkgs>,
}:

let
# TODO: use an ‘input pinner’ to lock in a stable Nixpkgs version
# <nixpkgs> uses the system’s Nixpkgs version which is impure.
pkgs = import nixpkgs {
inherit system;
overlays = [
(import ./nix/overlay)
(import ./nix/overlay/development.nix)
];
};
in
{
inherit (pkgs) zerostack;
default = pkgs.zerostack;
shell = pkgs.zerostack-dev-shell;
}
2 changes: 0 additions & 2 deletions scripts/sync-version.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ fi

echo "Syncing version ${VERSION} across packaging files..."

# flake.nix reads version from Cargo.toml via importTOML (no change needed)

# PKGBUILD
sed -i "s/^pkgver=.*/pkgver=${VERSION}/" "${ROOT_DIR}/packaging/aur/PKGBUILD"

Expand Down
1 change: 1 addition & 0 deletions shell.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(import ./release.nix { }).shell
12 changes: 12 additions & 0 deletions src/ui/input/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@ impl InputEditor {
}
}

/// Move the cursor to `pos` (a byte offset), clamped to a char boundary
/// within the buffer. Used when a mouse click places the cursor.
pub fn set_cursor(&mut self, pos: usize) {
let pos = pos.min(self.buffer.len());
self.cursor = if self.buffer.is_char_boundary(pos) {
pos
} else {
prev_char_boundary(&self.buffer, pos)
};
self.yank_pos = None;
}

pub fn clear_buffer(&mut self) {
self.buffer.clear();
self.cursor = 0;
Expand Down
26 changes: 22 additions & 4 deletions src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ fn refresh_display(
btw_in: u64,
btw_out: u64,
) -> io::Result<()> {
// Reconcile the input height first so the chat viewport is drawn against
// the size the input is about to occupy (avoids a stale separator when the
// input shrinks, or chat text hidden under it when the input grows).
renderer.sync_input_height(&input.buffer)?;
renderer.render_viewport()?;
let statusline_ctx = crate::ui::statusline::StatusContext {
loop_label,
Expand Down Expand Up @@ -1061,17 +1065,31 @@ pub async fn run_interactive(
continue;
}
UserEvent::ScrollUp => {
renderer.scroll_line_up();
// Scroll the input viewport first; once it is at the top,
// keep wheeling up to scroll back through the chat history.
if !renderer.input_scroll_up() {
renderer.scroll_line_up();
}
refresh_display(&mut renderer, &mut input, session, is_running, loop_label.as_deref(), context.current_prompt_name.as_deref(), perm_mode().as_deref(), chain_label_msg.as_deref(), btw_total_cost, btw_total_in, btw_total_out)?;
continue;
}
UserEvent::ScrollDown => {
renderer.scroll_line_down();
// Bring the chat history back down first, then the input.
if renderer.is_scrolling() {
renderer.scroll_line_down();
} else {
renderer.input_scroll_down();
}
refresh_display(&mut renderer, &mut input, session, is_running, loop_label.as_deref(), context.current_prompt_name.as_deref(), perm_mode().as_deref(), chain_label_msg.as_deref(), btw_total_cost, btw_total_in, btw_total_out)?;
continue;
}
UserEvent::MouseDown { row, col: _ } => {
if row < renderer.visible_lines() as u16
UserEvent::MouseDown { row, col } => {
// A click inside the input area moves the cursor there;
// otherwise it starts a chat-history text selection.
if let Some(pos) = renderer.input_cursor_for_click(row, col, &input.buffer) {
input.set_cursor(pos);
refresh_display(&mut renderer, &mut input, session, is_running, loop_label.as_deref(), context.current_prompt_name.as_deref(), perm_mode().as_deref(), chain_label_msg.as_deref(), btw_total_cost, btw_total_in, btw_total_out)?;
} else if row < renderer.visible_lines() as u16
&& let Some(idx) = renderer.buffer_line_at_row(row) {
renderer.selection_active = true;
renderer.selection_start = Some(idx);
Expand Down
Loading
Loading