Compare commits
10 Commits
7cb09c11da
...
c3ae848f54
| Author | SHA1 | Date | |
|---|---|---|---|
| c3ae848f54 | |||
| 1d5a04088b | |||
| a330412732 | |||
| 43015a41d8 | |||
| 29f922aaca | |||
| ee6970fed0 | |||
| 880c471ff6 | |||
| e166049bae | |||
| 2c05b64d51 | |||
| 86ac30c11d |
@@ -0,0 +1,44 @@
|
|||||||
|
name: Claude Code Review
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, ready_for_review, reopened]
|
||||||
|
# Optional: Only run on specific file changes
|
||||||
|
# paths:
|
||||||
|
# - "src/**/*.ts"
|
||||||
|
# - "src/**/*.tsx"
|
||||||
|
# - "src/**/*.js"
|
||||||
|
# - "src/**/*.jsx"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
claude-review:
|
||||||
|
# Optional: Filter by PR author
|
||||||
|
# if: |
|
||||||
|
# github.event.pull_request.user.login == 'external-contributor' ||
|
||||||
|
# github.event.pull_request.user.login == 'new-developer' ||
|
||||||
|
# github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: read
|
||||||
|
issues: read
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
|
||||||
|
- name: Run Claude Code Review
|
||||||
|
id: claude-review
|
||||||
|
uses: anthropics/claude-code-action@v1
|
||||||
|
with:
|
||||||
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||||
|
plugin_marketplaces: 'https://github.com/anthropics/claude-code.git'
|
||||||
|
plugins: 'code-review@claude-code-plugins'
|
||||||
|
prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}'
|
||||||
|
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
||||||
|
# or https://code.claude.com/docs/en/cli-reference for available options
|
||||||
|
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
name: Claude Code
|
||||||
|
|
||||||
|
on:
|
||||||
|
issue_comment:
|
||||||
|
types: [created]
|
||||||
|
pull_request_review_comment:
|
||||||
|
types: [created]
|
||||||
|
issues:
|
||||||
|
types: [opened, assigned]
|
||||||
|
pull_request_review:
|
||||||
|
types: [submitted]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
claude:
|
||||||
|
if: |
|
||||||
|
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
|
||||||
|
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
|
||||||
|
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
|
||||||
|
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: read
|
||||||
|
issues: read
|
||||||
|
id-token: write
|
||||||
|
actions: read # Required for Claude to read CI results on PRs
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
|
||||||
|
- name: Run Claude Code
|
||||||
|
id: claude
|
||||||
|
uses: anthropics/claude-code-action@v1
|
||||||
|
with:
|
||||||
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||||
|
|
||||||
|
# This is an optional setting that allows Claude to read CI results on PRs
|
||||||
|
additional_permissions: |
|
||||||
|
actions: read
|
||||||
|
|
||||||
|
# Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
|
||||||
|
# prompt: 'Update the pull request description to include a summary of changes.'
|
||||||
|
|
||||||
|
# Optional: Add claude_args to customize behavior and configuration
|
||||||
|
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
||||||
|
# or https://code.claude.com/docs/en/cli-reference for available options
|
||||||
|
# claude_args: '--allowed-tools Bash(gh pr:*)'
|
||||||
|
|
||||||
+380
-364
File diff suppressed because it is too large
Load Diff
+33
-4
@@ -72,6 +72,8 @@ pub enum Binding {
|
|||||||
},
|
},
|
||||||
/// A prefix sub-keymap (Emacs-style).
|
/// A prefix sub-keymap (Emacs-style).
|
||||||
Prefix(Arc<Keymap>),
|
Prefix(Arc<Keymap>),
|
||||||
|
/// A sequence of commands executed in order, concatenating their effects.
|
||||||
|
Sequence(Vec<(&'static str, Vec<String>)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A keymap maps key patterns to bindings (command names or prefix sub-keymaps).
|
/// A keymap maps key patterns to bindings (command names or prefix sub-keymaps).
|
||||||
@@ -121,6 +123,17 @@ impl Keymap {
|
|||||||
.insert(KeyPattern::Key(key, mods), Binding::Prefix(sub));
|
.insert(KeyPattern::Key(key, mods), Binding::Prefix(sub));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Bind a key to a sequence of commands (executed in order).
|
||||||
|
pub fn bind_seq(
|
||||||
|
&mut self,
|
||||||
|
key: KeyCode,
|
||||||
|
mods: KeyModifiers,
|
||||||
|
steps: Vec<(&'static str, Vec<String>)>,
|
||||||
|
) {
|
||||||
|
self.bindings
|
||||||
|
.insert(KeyPattern::Key(key, mods), Binding::Sequence(steps));
|
||||||
|
}
|
||||||
|
|
||||||
/// Bind a catch-all for any Char key.
|
/// Bind a catch-all for any Char key.
|
||||||
pub fn bind_any_char(&mut self, name: &'static str, args: Vec<String>) {
|
pub fn bind_any_char(&mut self, name: &'static str, args: Vec<String>) {
|
||||||
self.bindings
|
self.bindings
|
||||||
@@ -173,6 +186,14 @@ impl Keymap {
|
|||||||
Some(cmd.execute(ctx))
|
Some(cmd.execute(ctx))
|
||||||
}
|
}
|
||||||
Binding::Prefix(sub) => Some(vec![Box::new(SetTransientKeymap(sub.clone()))]),
|
Binding::Prefix(sub) => Some(vec![Box::new(SetTransientKeymap(sub.clone()))]),
|
||||||
|
Binding::Sequence(steps) => {
|
||||||
|
let mut effects: Vec<Box<dyn Effect>> = Vec::new();
|
||||||
|
for (name, args) in steps {
|
||||||
|
let cmd = registry.interactive(name, args, ctx).ok()?;
|
||||||
|
effects.extend(cmd.execute(ctx));
|
||||||
|
}
|
||||||
|
Some(effects)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -360,7 +381,11 @@ impl KeymapSet {
|
|||||||
// Drill into aggregated cell / view history / add row
|
// Drill into aggregated cell / view history / add row
|
||||||
normal.bind(KeyCode::Char('>'), none, "drill-into-cell");
|
normal.bind(KeyCode::Char('>'), none, "drill-into-cell");
|
||||||
normal.bind(KeyCode::Char('<'), none, "view-back");
|
normal.bind(KeyCode::Char('<'), none, "view-back");
|
||||||
normal.bind(KeyCode::Char('o'), none, "open-record-row");
|
normal.bind_seq(
|
||||||
|
KeyCode::Char('o'),
|
||||||
|
none,
|
||||||
|
vec![("add-record-row", vec![]), ("enter-edit-at-cursor", vec![])],
|
||||||
|
);
|
||||||
|
|
||||||
// Records mode toggle and prune toggle
|
// Records mode toggle and prune toggle
|
||||||
normal.bind(KeyCode::Char('R'), none, "toggle-records-mode");
|
normal.bind(KeyCode::Char('R'), none, "toggle-records-mode");
|
||||||
@@ -384,7 +409,11 @@ impl KeymapSet {
|
|||||||
normal.bind_prefix(KeyCode::Char('y'), none, Arc::new(y_map));
|
normal.bind_prefix(KeyCode::Char('y'), none, Arc::new(y_map));
|
||||||
|
|
||||||
let mut z_map = Keymap::new();
|
let mut z_map = Keymap::new();
|
||||||
z_map.bind(KeyCode::Char('Z'), none, "save-and-quit");
|
z_map.bind_seq(
|
||||||
|
KeyCode::Char('Z'),
|
||||||
|
none,
|
||||||
|
vec![("save", vec![]), ("force-quit", vec![])],
|
||||||
|
);
|
||||||
normal.bind_prefix(KeyCode::Char('Z'), none, Arc::new(z_map));
|
normal.bind_prefix(KeyCode::Char('Z'), none, Arc::new(z_map));
|
||||||
|
|
||||||
set.insert(ModeKey::Normal, Arc::new(normal));
|
set.insert(ModeKey::Normal, Arc::new(normal));
|
||||||
@@ -664,8 +693,8 @@ impl KeymapSet {
|
|||||||
let mut sm = Keymap::new();
|
let mut sm = Keymap::new();
|
||||||
sm.bind(KeyCode::Esc, none, "exit-search-mode");
|
sm.bind(KeyCode::Esc, none, "exit-search-mode");
|
||||||
sm.bind(KeyCode::Enter, none, "exit-search-mode");
|
sm.bind(KeyCode::Enter, none, "exit-search-mode");
|
||||||
sm.bind(KeyCode::Backspace, none, "search-pop-char");
|
sm.bind_args(KeyCode::Backspace, none, "pop-char", vec!["search".into()]);
|
||||||
sm.bind_any_char("search-append-char", vec![]);
|
sm.bind_any_char("append-char", vec!["search".into()]);
|
||||||
set.insert(ModeKey::SearchMode, Arc::new(sm));
|
set.insert(ModeKey::SearchMode, Arc::new(sm));
|
||||||
|
|
||||||
// ── Import wizard ────────────────────────────────────────────────
|
// ── Import wizard ────────────────────────────────────────────────
|
||||||
|
|||||||
+4
-1
@@ -506,7 +506,10 @@ mod tests {
|
|||||||
let mut app = two_col_model();
|
let mut app = two_col_model();
|
||||||
// Total rows: A, B, C + R0..R9 = 13 rows. Last row = 12.
|
// Total rows: A, B, C + R0..R9 = 13 rows. Last row = 12.
|
||||||
for i in 0..10 {
|
for i in 0..10 {
|
||||||
app.model.category_mut("Row").unwrap().add_item(&format!("R{i}"));
|
app.model
|
||||||
|
.category_mut("Row")
|
||||||
|
.unwrap()
|
||||||
|
.add_item(&format!("R{i}"));
|
||||||
}
|
}
|
||||||
app.term_height = 13; // ~5 visible rows
|
app.term_height = 13; // ~5 visible rows
|
||||||
app.model.active_view_mut().selected = (0, 0);
|
app.model.active_view_mut().selected = (0, 0);
|
||||||
|
|||||||
+9
-4
@@ -96,7 +96,11 @@ impl Effect for RemoveFormula {
|
|||||||
pub struct EnterEditAtCursor;
|
pub struct EnterEditAtCursor;
|
||||||
impl Effect for EnterEditAtCursor {
|
impl Effect for EnterEditAtCursor {
|
||||||
fn apply(&self, app: &mut App) {
|
fn apply(&self, app: &mut App) {
|
||||||
let ctx = app.cmd_context(crossterm::event::KeyCode::Null, crossterm::event::KeyModifiers::NONE);
|
app.rebuild_layout();
|
||||||
|
let ctx = app.cmd_context(
|
||||||
|
crossterm::event::KeyCode::Null,
|
||||||
|
crossterm::event::KeyModifiers::NONE,
|
||||||
|
);
|
||||||
let value = ctx.display_value.clone();
|
let value = ctx.display_value.clone();
|
||||||
drop(ctx);
|
drop(ctx);
|
||||||
app.buffers.insert("edit".to_string(), value);
|
app.buffers.insert("edit".to_string(), value);
|
||||||
@@ -472,9 +476,10 @@ pub struct SetDrillPendingEdit {
|
|||||||
impl Effect for SetDrillPendingEdit {
|
impl Effect for SetDrillPendingEdit {
|
||||||
fn apply(&self, app: &mut App) {
|
fn apply(&self, app: &mut App) {
|
||||||
if let Some(drill) = &mut app.drill_state {
|
if let Some(drill) = &mut app.drill_state {
|
||||||
drill
|
drill.pending_edits.insert(
|
||||||
.pending_edits
|
(self.record_idx, self.col_name.clone()),
|
||||||
.insert((self.record_idx, self.col_name.clone()), self.new_value.clone());
|
self.new_value.clone(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -59,7 +59,7 @@ impl<'a> GridWidget<'a> {
|
|||||||
let n_col_levels = layout.col_cats.len().max(1);
|
let n_col_levels = layout.col_cats.len().max(1);
|
||||||
let n_row_levels = layout.row_cats.len().max(1);
|
let n_row_levels = layout.row_cats.len().max(1);
|
||||||
|
|
||||||
let col_widths = compute_col_widths(self.model, &layout, fmt_comma, fmt_decimals);
|
let col_widths = compute_col_widths(self.model, layout, fmt_comma, fmt_decimals);
|
||||||
|
|
||||||
// ── Adaptive row header widths ───────────────────────────────
|
// ── Adaptive row header widths ───────────────────────────────
|
||||||
let data_row_items: Vec<&Vec<String>> = layout
|
let data_row_items: Vec<&Vec<String>> = layout
|
||||||
|
|||||||
+1
-9
@@ -4,20 +4,12 @@ use ratatui::{
|
|||||||
style::{Color, Modifier, Style},
|
style::{Color, Modifier, Style},
|
||||||
widgets::Widget,
|
widgets::Widget,
|
||||||
};
|
};
|
||||||
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
use crate::model::Model;
|
use crate::model::Model;
|
||||||
use crate::ui::app::AppMode;
|
use crate::ui::app::AppMode;
|
||||||
use crate::view::Axis;
|
use crate::view::Axis;
|
||||||
|
|
||||||
fn axis_display(axis: Axis) -> (&'static str, Color) {
|
|
||||||
match axis {
|
|
||||||
Axis::Row => ("↕", Color::Green),
|
|
||||||
Axis::Column => ("↔", Color::Blue),
|
|
||||||
Axis::Page => ("☰", Color::Magenta),
|
|
||||||
Axis::None => ("∅", Color::DarkGray),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TileBar<'a> {
|
pub struct TileBar<'a> {
|
||||||
pub model: &'a Model,
|
pub model: &'a Model,
|
||||||
pub mode: &'a AppMode,
|
pub mode: &'a AppMode,
|
||||||
|
|||||||
+4
-1
@@ -676,7 +676,10 @@ mod tests {
|
|||||||
let region_col = cols.iter().position(|c| c == "Region").unwrap();
|
let region_col = cols.iter().position(|c| c == "Region").unwrap();
|
||||||
let key = layout.cell_key(0, region_col).unwrap();
|
let key = layout.cell_key(0, region_col).unwrap();
|
||||||
let display = layout.resolve_display(&key).unwrap();
|
let display = layout.resolve_display(&key).unwrap();
|
||||||
assert!(!display.is_empty(), "Region column should resolve to a value");
|
assert!(
|
||||||
|
!display.is_empty(),
|
||||||
|
"Region column should resolve to a value"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user