Skip to content

Commit ffa6d9e

Browse files
authored
add cli flag to open files tab with selected file (#2746)
1 parent a6d6f31 commit ffa6d9e

File tree

7 files changed

+77
-19
lines changed

7 files changed

+77
-19
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1919
* dx: `make check` checks Cargo.toml dependency ordering using `cargo sort` [[@naseschwarz](https://github.com/naseschwarz)]
2020
* add `use_selection_fg` to theme file to allow customizing selection foreground color [[@Upsylonbare](https://github.com/Upsylonbare)] ([#2515](https://github.com/gitui-org/gitui/pull/2515))
2121
* Add "go to line" command for the blame view [[@andrea-berling](https://github.com/andrea-berling)] ([#2262](https://github.com/extrawurst/gitui/pull/2262))
22+
* add `--file` cli flag to open the files tab with the given file already selected [[@laktak](https://github.com/laktak)] ([#2510](https://github.com/gitui-org/gitui/issues/2510))
2223

2324
### Changed
2425
* improve error messages [[@acuteenvy](https://github.com/acuteenvy)] ([#2617](https://github.com/gitui-org/gitui/pull/2617))

src/app.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::{
22
accessors,
3+
args::CliArgs,
34
cmdbar::CommandBar,
45
components::{
56
command_pump, event_pump, CommandInfo, Component,
@@ -151,13 +152,14 @@ impl App {
151152
///
152153
#[allow(clippy::too_many_lines)]
153154
pub fn new(
154-
repo: RepoPathRef,
155+
cliargs: CliArgs,
155156
sender_git: Sender<AsyncGitNotification>,
156157
sender_app: Sender<AsyncAppNotification>,
157158
input: Input,
158159
theme: Theme,
159160
key_config: KeyConfig,
160161
) -> Result<Self> {
162+
let repo = RefCell::new(cliargs.repo_path.clone());
161163
log::trace!("open repo at: {:?}", &repo);
162164

163165
let repo_path_text =
@@ -173,7 +175,20 @@ impl App {
173175
sender_app,
174176
};
175177

176-
let tab = env.options.borrow().current_tab();
178+
let mut select_file: Option<PathBuf> = None;
179+
let tab = if let Some(file) = cliargs.select_file {
180+
// convert to relative git path
181+
if let Ok(abs) = file.canonicalize() {
182+
if let Ok(path) = abs.strip_prefix(
183+
env.repo.borrow().gitpath().canonicalize()?,
184+
) {
185+
select_file = Some(Path::new(".").join(path));
186+
}
187+
}
188+
2
189+
} else {
190+
env.options.borrow().current_tab()
191+
};
177192

178193
let mut app = Self {
179194
input,
@@ -218,7 +233,7 @@ impl App {
218233
status_tab: Status::new(&env),
219234
stashing_tab: Stashing::new(&env),
220235
stashlist_tab: StashList::new(&env),
221-
files_tab: FilesTab::new(&env),
236+
files_tab: FilesTab::new(&env, select_file),
222237
goto_line_popup: GotoLinePopup::new(&env),
223238
tab: 0,
224239
queue: env.queue,

src/args.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@ const LOG_FILE_FLAG_ID: &str = "logfile";
1717
const LOGGING_FLAG_ID: &str = "logging";
1818
const THEME_FLAG_ID: &str = "theme";
1919
const WORKDIR_FLAG_ID: &str = "workdir";
20+
const FILE_FLAG_ID: &str = "file";
2021
const GIT_DIR_FLAG_ID: &str = "directory";
2122
const WATCHER_FLAG_ID: &str = "watcher";
2223
const DEFAULT_THEME: &str = "theme.ron";
2324
const DEFAULT_GIT_DIR: &str = ".";
2425

26+
#[derive(Clone)]
2527
pub struct CliArgs {
2628
pub theme: PathBuf,
29+
pub select_file: Option<PathBuf>,
2730
pub repo_path: RepoPath,
2831
pub notify_watcher: bool,
2932
}
@@ -51,6 +54,10 @@ pub fn process_cmdline() -> Result<CliArgs> {
5154
PathBuf::from,
5255
);
5356

57+
let select_file = arg_matches
58+
.get_one::<String>(FILE_FLAG_ID)
59+
.map(PathBuf::from);
60+
5461
let repo_path = if let Some(w) = workdir {
5562
RepoPath::Workdir { gitdir, workdir: w }
5663
} else {
@@ -75,6 +82,7 @@ pub fn process_cmdline() -> Result<CliArgs> {
7582

7683
Ok(CliArgs {
7784
theme,
85+
select_file,
7886
repo_path,
7987
notify_watcher,
8088
})
@@ -129,6 +137,13 @@ fn app() -> ClapApp {
129137
.long("bugreport")
130138
.action(clap::ArgAction::SetTrue),
131139
)
140+
.arg(
141+
Arg::new(FILE_FLAG_ID)
142+
.help("Select the file in the file tab")
143+
.short('f')
144+
.long("file")
145+
.num_args(1),
146+
)
132147
.arg(
133148
Arg::new(GIT_DIR_FLAG_ID)
134149
.help("Set the git directory")

src/components/revision_files.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ use ratatui::{
3030
Frame,
3131
};
3232
use std::{borrow::Cow, fmt::Write};
33-
use std::{collections::BTreeSet, path::Path};
33+
use std::{
34+
collections::BTreeSet,
35+
path::{Path, PathBuf},
36+
};
3437
use unicode_truncate::UnicodeTruncateStr;
3538
use unicode_width::UnicodeWidthStr;
3639

@@ -53,11 +56,15 @@ pub struct RevisionFilesComponent {
5356
revision: Option<CommitInfo>,
5457
focus: Focus,
5558
key_config: SharedKeyConfig,
59+
select_file: Option<PathBuf>,
5660
}
5761

5862
impl RevisionFilesComponent {
5963
///
60-
pub fn new(env: &Environment) -> Self {
64+
pub fn new(
65+
env: &Environment,
66+
select_file: Option<PathBuf>,
67+
) -> Self {
6168
Self {
6269
queue: env.queue.clone(),
6370
tree: FileTree::default(),
@@ -72,6 +79,7 @@ impl RevisionFilesComponent {
7279
focus: Focus::Tree,
7380
key_config: env.key_config.clone(),
7481
repo: env.repo.clone(),
82+
select_file,
7583
visible: false,
7684
}
7785
}
@@ -134,6 +142,12 @@ impl RevisionFilesComponent {
134142
self.tree.collapse_but_root();
135143

136144
self.files = Some(last);
145+
146+
let select_file = self.select_file.clone();
147+
self.select_file = None;
148+
if let Some(file) = select_file {
149+
self.find_file(file.as_path());
150+
}
137151
}
138152
} else if let Some(rev) = &self.revision {
139153
self.request_files(rev.id);

src/main.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,10 @@ mod tabs;
7979
mod ui;
8080
mod watcher;
8181

82-
use crate::{app::App, args::process_cmdline};
82+
use crate::{
83+
app::App,
84+
args::{process_cmdline, CliArgs},
85+
};
8386
use anyhow::{anyhow, bail, Result};
8487
use app::QuitState;
8588
use asyncgit::{
@@ -102,7 +105,6 @@ use scopeguard::defer;
102105
use scopetime::scope_time;
103106
use spinner::Spinner;
104107
use std::{
105-
cell::RefCell,
106108
io::{self, Stdout},
107109
panic,
108110
path::Path,
@@ -180,8 +182,8 @@ fn main() -> Result<()> {
180182

181183
set_panic_handler()?;
182184

183-
let mut repo_path = cliargs.repo_path;
184-
let mut terminal = start_terminal(io::stdout(), &repo_path)?;
185+
let mut terminal =
186+
start_terminal(io::stdout(), &cliargs.repo_path)?;
185187
let input = Input::new();
186188

187189
let updater = if cliargs.notify_watcher {
@@ -190,10 +192,12 @@ fn main() -> Result<()> {
190192
Updater::Ticker
191193
};
192194

195+
let mut args = cliargs;
196+
193197
loop {
194198
let quit_state = run_app(
195199
app_start,
196-
repo_path.clone(),
200+
args.clone(),
197201
theme.clone(),
198202
key_config.clone(),
199203
&input,
@@ -203,7 +207,12 @@ fn main() -> Result<()> {
203207

204208
match quit_state {
205209
QuitState::OpenSubmodule(p) => {
206-
repo_path = p;
210+
args = CliArgs {
211+
repo_path: p,
212+
select_file: None,
213+
theme: args.theme,
214+
notify_watcher: args.notify_watcher,
215+
}
207216
}
208217
_ => break,
209218
}
@@ -214,7 +223,7 @@ fn main() -> Result<()> {
214223

215224
fn run_app(
216225
app_start: Instant,
217-
repo: RepoPath,
226+
cliargs: CliArgs,
218227
theme: Theme,
219228
key_config: KeyConfig,
220229
input: &Input,
@@ -228,8 +237,9 @@ fn run_app(
228237

229238
let (rx_ticker, rx_watcher) = match updater {
230239
Updater::NotifyWatcher => {
231-
let repo_watcher =
232-
RepoWatcher::new(repo_work_dir(&repo)?.as_str());
240+
let repo_watcher = RepoWatcher::new(
241+
repo_work_dir(&cliargs.repo_path)?.as_str(),
242+
);
233243

234244
(never(), repo_watcher.receiver())
235245
}
@@ -239,7 +249,7 @@ fn run_app(
239249
let spinner_ticker = tick(SPINNER_INTERVAL);
240250

241251
let mut app = App::new(
242-
RefCell::new(repo),
252+
cliargs,
243253
tx_git,
244254
tx_app,
245255
input.clone(),

src/popups/revision_files.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ impl RevisionFilesPopup {
3838
///
3939
pub fn new(env: &Environment) -> Self {
4040
Self {
41-
files: RevisionFilesComponent::new(env),
41+
files: RevisionFilesComponent::new(env, None),
4242
visible: false,
4343
key_config: env.key_config.clone(),
4444
open_request: None,

src/tabs/files.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::path::Path;
1+
use std::path::{Path, PathBuf};
22

33
use crate::{
44
app::Environment,
@@ -19,10 +19,13 @@ pub struct FilesTab {
1919

2020
impl FilesTab {
2121
///
22-
pub fn new(env: &Environment) -> Self {
22+
pub fn new(
23+
env: &Environment,
24+
select_file: Option<PathBuf>,
25+
) -> Self {
2326
Self {
2427
visible: false,
25-
files: RevisionFilesComponent::new(env),
28+
files: RevisionFilesComponent::new(env, select_file),
2629
repo: env.repo.clone(),
2730
}
2831
}

0 commit comments

Comments
 (0)