more general palette code, dedupe some main.rs code, start of branch switcher

This commit is contained in:
Scott Chacon 2023-03-12 13:16:30 -07:00
parent 01a5c572dc
commit 524591821a
3 changed files with 90 additions and 80 deletions

View File

@ -177,15 +177,7 @@ fn list_sessions(
handle: tauri::AppHandle, handle: tauri::AppHandle,
project_id: &str, project_id: &str,
) -> Result<Vec<sessions::Session>, Error> { ) -> Result<Vec<sessions::Session>, Error> {
let app_state = handle.state::<App>(); let repo = repo_for_project(handle, project_id)?;
let repo = repositories::Repository::open(
&app_state.projects_storage,
&app_state.users_storage,
project_id,
)
.with_context(|| format!("Failed to open repository for project {}", project_id))?;
let sessions = repo let sessions = repo
.sessions() .sessions()
.with_context(|| format!("Failed to list sessions for project {}", project_id))?; .with_context(|| format!("Failed to list sessions for project {}", project_id))?;
@ -338,16 +330,8 @@ fn list_session_files(
session_id: &str, session_id: &str,
paths: Option<Vec<&str>>, paths: Option<Vec<&str>>,
) -> Result<HashMap<String, String>, Error> { ) -> Result<HashMap<String, String>, Error> {
let app_state = handle.state::<App>(); let repo = repo_for_project(handle, project_id)?;
let repo = repositories::Repository::open(
&app_state.projects_storage,
&app_state.users_storage,
project_id,
)?;
let files = repo.files(session_id, paths)?; let files = repo.files(session_id, paths)?;
Ok(files) Ok(files)
} }
@ -357,16 +341,8 @@ fn list_deltas(
project_id: &str, project_id: &str,
session_id: &str, session_id: &str,
) -> Result<HashMap<String, Vec<Delta>>, Error> { ) -> Result<HashMap<String, Vec<Delta>>, Error> {
let app_state = handle.state::<App>(); let repo = repo_for_project(handle, project_id)?;
let repo = repositories::Repository::open(
&app_state.projects_storage,
&app_state.users_storage,
project_id,
)?;
let deltas = repo.deltas(session_id)?; let deltas = repo.deltas(session_id)?;
Ok(deltas) Ok(deltas)
} }
@ -375,29 +351,14 @@ fn git_status(
handle: tauri::AppHandle, handle: tauri::AppHandle,
project_id: &str, project_id: &str,
) -> Result<HashMap<String, String>, Error> { ) -> Result<HashMap<String, String>, Error> {
let app_state = handle.state::<App>(); let repo = repo_for_project(handle, project_id)?;
let repo = repositories::Repository::open(
&app_state.projects_storage,
&app_state.users_storage,
project_id,
)?;
let files = repo.status().with_context(|| "Failed to get git status")?; let files = repo.status().with_context(|| "Failed to get git status")?;
Ok(files) Ok(files)
} }
#[tauri::command] #[tauri::command]
fn git_file_paths(handle: tauri::AppHandle, project_id: &str) -> Result<Vec<String>, Error> { fn git_file_paths(handle: tauri::AppHandle, project_id: &str) -> Result<Vec<String>, Error> {
let app_state = handle.state::<App>(); let repo = repo_for_project(handle, project_id)?;
let repo = repositories::Repository::open(
&app_state.projects_storage,
&app_state.users_storage,
project_id,
)?;
let files = repo let files = repo
.file_paths() .file_paths()
.with_context(|| "Failed to get file paths")?; .with_context(|| "Failed to get file paths")?;
@ -411,6 +372,18 @@ fn git_match_paths(
project_id: &str, project_id: &str,
match_pattern: &str, match_pattern: &str,
) -> Result<Vec<String>, Error> { ) -> Result<Vec<String>, Error> {
let repo = repo_for_project(handle, project_id)?;
let files = repo
.match_file_paths(match_pattern)
.with_context(|| "Failed to get file paths")?;
Ok(files)
}
fn repo_for_project(
handle: tauri::AppHandle,
project_id: &str,
) -> Result<repositories::Repository, Error> {
let app_state = handle.state::<App>(); let app_state = handle.state::<App>();
let repo = repositories::Repository::open( let repo = repositories::Repository::open(
@ -419,10 +392,15 @@ fn git_match_paths(
project_id, project_id,
)?; )?;
let files = repo Ok(repo)
.match_file_paths(match_pattern) }
.with_context(|| "Failed to get file paths")?;
#[tauri::command]
fn git_branches(handle: tauri::AppHandle, project_id: &str) -> Result<Vec<String>, Error> {
let repo = repo_for_project(handle, project_id)?;
let files = repo
.branches()
.with_context(|| "Failed to get file paths")?;
Ok(files) Ok(files)
} }
@ -434,14 +412,7 @@ fn git_commit(
files: Vec<&str>, files: Vec<&str>,
push: bool, push: bool,
) -> Result<bool, Error> { ) -> Result<bool, Error> {
let app_state = handle.state::<App>(); let repo = repo_for_project(handle, project_id)?;
let repo = repositories::Repository::open(
&app_state.projects_storage,
&app_state.users_storage,
project_id,
)?;
let success = repo let success = repo
.commit(message, files, push) .commit(message, files, push)
.with_context(|| "Failed to commit")?; .with_context(|| "Failed to commit")?;
@ -563,6 +534,7 @@ fn main() {
git_status, git_status,
git_file_paths, git_file_paths,
git_match_paths, git_match_paths,
git_branches,
git_commit git_commit
]); ]);

View File

@ -156,6 +156,15 @@ impl Repository {
} }
} }
pub fn branches(&self) -> Result<Vec<String>> {
let mut branches = vec![];
for branch in self.git_repository.branches(None)? {
let (branch, _) = branch?;
branches.push(branch.name()?.unwrap().to_string());
}
Ok(branches)
}
// get file status from git // get file status from git
pub fn status(&self) -> Result<HashMap<String, String>> { pub fn status(&self) -> Result<HashMap<String, String>> {
let mut options = git2::StatusOptions::new(); let mut options = git2::StatusOptions::new();

View File

@ -11,6 +11,7 @@
import { shortPath } from '$lib/paths'; import { shortPath } from '$lib/paths';
import { currentProject } from '$lib/current_project'; import { currentProject } from '$lib/current_project';
import type { Project } from '$lib/projects'; import type { Project } from '$lib/projects';
import { placeholder } from '@codemirror/view';
let showPalette = <string | false>false; let showPalette = <string | false>false;
let keysDown = <string[]>[]; let keysDown = <string[]>[];
@ -19,6 +20,7 @@
let changedFiles = {}; let changedFiles = {};
let commitMessage = ''; let commitMessage = '';
let commitMessageInput: HTMLElement; let commitMessageInput: HTMLElement;
let paletteMode = 'command';
const listFiles = (params: { projectId: string }) => const listFiles = (params: { projectId: string }) =>
invoke<Record<string, string>>('git_status', params); invoke<Record<string, string>>('git_status', params);
@ -26,6 +28,9 @@
const matchFiles = (params: { projectId: string; matchPattern: string }) => const matchFiles = (params: { projectId: string; matchPattern: string }) =>
invoke<Array<string>>('git_match_paths', params); invoke<Array<string>>('git_match_paths', params);
const listBranches = (params: { projectId: string }) =>
invoke<Array<string>>('git_branches', params);
const listProjects = () => invoke<Project[]>('list_projects'); const listProjects = () => invoke<Project[]>('list_projects');
const commit = (params: { const commit = (params: {
@ -44,6 +49,7 @@
break; break;
case 'Escape': case 'Escape':
showPalette = false; showPalette = false;
paletteMode = 'command';
break; break;
case 'ArrowDown': case 'ArrowDown':
if (showPalette == 'command') { if (showPalette == 'command') {
@ -78,6 +84,9 @@
if (keysDown.includes('e')) { if (keysDown.includes('e')) {
executeCommand('contact'); executeCommand('contact');
} }
if (keysDown.includes('r')) {
executeCommand('branch');
}
} }
} }
@ -170,7 +179,8 @@
case 'bookmark': case 'bookmark':
break; break;
case 'branch': case 'branch':
showBranch = true; showPalette = 'command';
branchSwitcher();
break; break;
} }
} }
@ -224,11 +234,11 @@
if (!showCommand) { if (!showCommand) {
search = ''; search = '';
} }
if (searchValue.length == 0) { if (searchValue.length == 0 && paletteMode == 'command') {
updateMenu([]); updateMenu([]);
return; return;
} }
if ($currentProject) { if ($currentProject && searchValue.length > 0) {
const searchPattern = '.*' + Array.from(searchValue).join('(.*)'); const searchPattern = '.*' + Array.from(searchValue).join('(.*)');
matchFiles({ projectId: $currentProject.id, matchPattern: searchPattern }).then((files) => { matchFiles({ projectId: $currentProject.id, matchPattern: searchPattern }).then((files) => {
let searchResults = []; let searchResults = [];
@ -240,6 +250,20 @@
} }
} }
function branchSwitcher() {
console.log('branchSwitcher', $currentProject);
paletteMode = 'branch';
if ($currentProject) {
listBranches({ projectId: $currentProject.id }).then((refs) => {
let branches = <Object[]>[];
refs.forEach((b) => {
branches.push({ text: b, icon: BranchIcon });
});
menuItems = branches;
});
}
}
function updateMenu(searchResults: Array<{ text: string }>) { function updateMenu(searchResults: Array<{ text: string }>) {
if (searchResults.length == 0) { if (searchResults.length == 0) {
menuItems = commandList(); menuItems = commandList();
@ -299,29 +323,34 @@
background-color: rgba(24, 24, 27, 0.60); background-color: rgba(24, 24, 27, 0.60);
border: 0.5px solid rgba(63, 63, 70, 0.50);" border: 0.5px solid rgba(63, 63, 70, 0.50);"
> >
<div class="relative"> {#if paletteMode == 'command'}
<svg <div class="relative">
class="pointer-events-none absolute top-3.5 left-4 h-5 w-5 text-zinc-500" <svg
fill="none" class="pointer-events-none absolute top-3.5 left-4 h-5 w-5 text-zinc-500"
viewBox="0 0 24 24" fill="none"
stroke-width="1.5" viewBox="0 0 24 24"
stroke="currentColor" stroke-width="1.5"
aria-hidden="true" stroke="currentColor"
> aria-hidden="true"
<path >
stroke-linecap="round" <path
stroke-linejoin="round" stroke-linecap="round"
d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z" stroke-linejoin="round"
d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z"
/>
</svg>
<input
id="command"
type="text"
bind:value={search}
class="h-12 w-full border-0 bg-transparent pl-11 pr-4 text-white focus:ring-0 sm:text-sm"
placeholder="Search..."
/> />
</svg> </div>
<input {/if}
id="command" {#if paletteMode == 'branch'}
type="text" <div class="text-lg p-4">Branch Switcher</div>
bind:value={search} {/if}
class="h-12 w-full border-0 bg-transparent pl-11 pr-4 text-white focus:ring-0 sm:text-sm"
placeholder="Search..."
/>
</div>
<!-- Default state, show/hide based on command palette state. --> <!-- Default state, show/hide based on command palette state. -->
<ul class="scroll-py-2 divide-y divide-zinc-500 divide-opacity-20 overflow-y-auto"> <ul class="scroll-py-2 divide-y divide-zinc-500 divide-opacity-20 overflow-y-auto">