Skip to content

Commit

Permalink
Add text search (#4)
Browse files Browse the repository at this point in the history
* feat: Add detail mode

* feat: Add focus mode and unfocus mode color style

* feat: Add default color theme

* feat: Add default color theme

* feat: Add more description to README.md

* feat: add .vscodecounter to .gitignore

* feat: Use utf-8 decode title instead

* feat: block detail mode if not selected any item

* chore: remove unused import and rename internal variables

* feat: Add search bar action

* chore: remove unused import

* feat: Add macors for sql generation

* feat: Add search with plain text

* feat: Add Searching feature
  • Loading branch information
MissterHao authored Nov 18, 2022
1 parent e686374 commit 4292faf
Show file tree
Hide file tree
Showing 27 changed files with 523 additions and 87 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ Cargo.lock

# Developer
.vscode/**
.vscode
.vscode
.VSCodeCounter
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ crossbeam-channel = "0.5.6"
thiserror = "1.0.37"
rusqlite = { version = "0.28.0", features = ["bundled"] }
unicode-width = "0.1.10"
regex = "1.7.0"


[profile.release]
Expand Down
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@ This is an ultimate unify vscode entry point.

## What is a workspaces organizer?

After months of or even years of hard working, have you notice that there are tons of folder which are open by vscode before?
You only want to find out a small experimental project in the workspaces history list but it hard to find because of the numbers of list.

**Ruscode** is a best soluation for you!

You can give your workspace tags to help you manage your workspaces.
You can search your workspaces by path, by folder name, or by tags which you gave before.
You can use terminal-UI application with beautiful color theme without hurting your eyes.

Awesome!

## Table of contents

- [📦 Install](#install)
Expand All @@ -28,6 +39,20 @@ This is an ultimate unify vscode entry point.
- [✨ Creator](#creator)
- [🌈 Contributors](#contributors)

## 🏹 Usage

There are two mode in management page:
+ Search Mode
+ Detail Mode

You can use arrow key to change between these two modes.
Also, you can find more detail of help text in the middle of screen.
<!-- A GIF to explain how to change mode -->

### Search Mode

### Detail Mode


## Licence
MIT
Expand All @@ -37,3 +62,7 @@ MIT

## Contributors



## 🌟 Star History
[![Star History Chart](https://api.star-history.com/svg?repos=MissterHao/ruscode&type=Date)](https://star-history.com/#MissterHao/ruscode&Date)
121 changes: 110 additions & 11 deletions src/application/app.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use std::fmt;
use std::{fmt, vec};

use crate::{
common::system::SystemPaths,
domain::{
entity::workspace::Workspace,
searching::parse::SearchingStrategy,
system::{init::init_application_folders, scan::scan_workspaces_path},
},
infrastructure::repository::{
Expand Down Expand Up @@ -32,13 +33,27 @@ impl fmt::Display for ApplicationStatus {
}
}

#[derive(Clone, Copy)]
pub enum ApplicationControlMode {
SearchMode,
DetailMode,
}

impl Default for ApplicationControlMode {
fn default() -> Self {
Self::SearchMode
}
}

pub struct App<'a> {
pub title: &'a str,
pub tabs: TabsState<'a>,
pub status: ApplicationStatus,
pub control_mode: ApplicationControlMode,
pub show_splash_screen: bool,
pub workspaces: StatefulList<Workspace>,
pub search_text: String,
workspaces_source: Vec<Workspace>,
}

impl<'a> App<'a> {
Expand All @@ -47,9 +62,11 @@ impl<'a> App<'a> {
title,
tabs: TabsState::new(vec!["Workspaces", "Settings"]),
status: ApplicationStatus::PrepareEnvironment,
control_mode: ApplicationControlMode::default(),
show_splash_screen: show_splash_screen,
workspaces: StatefulList::with_items(vec![]),
search_text: String::new(),
workspaces_source: vec![],
}
}

Expand All @@ -61,29 +78,109 @@ impl<'a> App<'a> {
self.tabs.next();
}

pub fn on_up(&mut self) {
self.workspaces.previous();
pub fn enter_detail_mode(&mut self) {
if !self.workspaces.has_selected_item() {
return;
};

match self.control_mode {
ApplicationControlMode::SearchMode => {
self.control_mode = ApplicationControlMode::DetailMode;
}
_ => {}
}
}

pub fn on_down(&mut self) {
self.workspaces.next();
pub fn enter_search_mode(&mut self) {
match self.control_mode {
ApplicationControlMode::DetailMode => {
self.control_mode = ApplicationControlMode::SearchMode;
}
_ => {}
}
}

pub fn enter_in_workspace(&mut self) {}
pub fn on_up_list(&mut self) {
match self.control_mode {
ApplicationControlMode::SearchMode => {
self.workspaces.previous();
}
ApplicationControlMode::DetailMode => {}
}
}

pub fn on_down_list(&mut self) {
match self.control_mode {
ApplicationControlMode::SearchMode => {
self.workspaces.next();
}
ApplicationControlMode::DetailMode => {}
}
}

pub fn on_enter(&mut self) {
match self.control_mode {
ApplicationControlMode::SearchMode => self.open_workspace(),
ApplicationControlMode::DetailMode => self.enter_new_tag(),
}
}

pub fn on_backspace(&mut self) {
match self.control_mode {
ApplicationControlMode::SearchMode => {
self.search_text.pop();
self.workspaces
.change_item_source(self.filtered_workspaces());
}
ApplicationControlMode::DetailMode => {
todo!()
}
}
}

pub fn filtered_workspaces(&self) -> Vec<Workspace> {
let strategy: SearchingStrategy = self.search_text.clone().into();

match strategy.searching_type {
crate::domain::searching::parse::SearchingStrategyType::All => {
self.workspaces_source.clone()
}
crate::domain::searching::parse::SearchingStrategyType::Tags => todo!(),
crate::domain::searching::parse::SearchingStrategyType::PlainText => self
.workspaces_source
.clone()
.iter()
.filter(|x| x.path.contains(&self.search_text))
.map(|x| x.clone())
.collect(),
crate::domain::searching::parse::SearchingStrategyType::PlainTextMixTags => todo!(),
}
}

/// Open workspace by vscode
fn open_workspace(&mut self) {}

/// Enter new tag for selected Workspace
fn enter_new_tag(&mut self) {}

//
pub fn on_key(&mut self, c: char) {
match c {
't' => {}
_ => {}
match self.control_mode {
ApplicationControlMode::SearchMode => self.on_input_search_text(c),
ApplicationControlMode::DetailMode => todo!(),
}
}

pub fn on_tick(&mut self) {}
fn on_input_search_text(&mut self, c: char) {
self.search_text.push(c);
}

/// Scan all workspace record generated by vscode
pub fn scan_workspaces(&mut self) -> Result<Vec<Workspace>, ApplicationError> {
Ok(scan_workspaces_path())
}

/// Create database if not exist
fn create_database(&self, path: &str) -> Result<(), DatabaseError> {
create_database(path)?;
Ok(())
Expand All @@ -105,10 +202,12 @@ impl<'a> App<'a> {
let ret = WorkspaceRepository::sync_to_database(&workspaces)
.expect("Syncing workspaces data failed.");

self.workspaces.items = ret;
self.workspaces_source = ret;

Ok(())
}

/// Manage all ApplicationStatus transition
pub fn state_change(&mut self, next_state: ApplicationStatus) {
match (self.status, next_state) {
// Starts from SyncData
Expand Down
1 change: 1 addition & 0 deletions src/application/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use thiserror::Error;

#[derive(Error, Debug)]
#[allow(dead_code)]
pub enum ApplicationError {
#[error("Database file can't create at `{0}`")]
InitializeDatabaseFailed(String),
Expand Down
10 changes: 6 additions & 4 deletions src/application/manage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use crossterm::{
use std::{
error::Error,
io,
sync::{Arc, Mutex},
time::{Duration, Instant},
};
use tui::{
Expand Down Expand Up @@ -60,10 +59,13 @@ fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<(
match key.code {
KeyCode::Esc => app.on_escape_application(),
KeyCode::Tab => app.next_tab(),
KeyCode::Up => app.on_up(),
KeyCode::Down => app.on_down(),
KeyCode::Up => app.on_up_list(),
KeyCode::Down => app.on_down_list(),
KeyCode::Right => app.enter_detail_mode(),
KeyCode::Left => app.enter_search_mode(),
KeyCode::Char(c) => app.on_key(c),
KeyCode::Enter => app.enter_in_workspace(),
KeyCode::Enter => app.on_enter(),
KeyCode::Backspace => app.on_backspace(),
_ => {}
}
}
Expand Down
36 changes: 30 additions & 6 deletions src/application/stateful_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,34 @@ where
}
}

pub fn change_item_source(&mut self, items: Vec<T>) {
self.items = items;
match self.state.selected() {
Some(curr) => {
if curr > self.items.len() {
self.state.select(Some(0));
}
}
None => self.state.select(None),
}
}

pub fn has_selected_item(&self) -> bool {
match self.state.selected() {
Some(_) => true,
None => false,
}
}

#[allow(dead_code)]
pub fn unselected(&mut self) {
self.state.select(None);
}

pub fn next(&mut self) {
// if self.items.len() <= 0 {
// return;
// }
if self.items.len() <= 0 {
return;
}

let i = match self.state.selected() {
Some(i) => {
Expand All @@ -39,9 +63,9 @@ where
}

pub fn previous(&mut self) {
// if self.items.len() <= 0 {
// return;
// }
if self.items.len() <= 0 {
return;
}
let i = match self.state.selected() {
Some(i) => {
if i == 0 {
Expand Down
2 changes: 1 addition & 1 deletion src/common/system.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::common::text::strip_trailing_newline;
use std::process::Command;
use std::str;
use std::{process::Command, str::FromStr};

pub struct SystemPaths {}

Expand Down
2 changes: 2 additions & 0 deletions src/domain/entity/tag.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#[derive(Debug)]
#[allow(dead_code)]
pub struct Tag {
name: String,
}

impl Tag {
#[allow(dead_code)]
pub fn new() -> Self {
Tag {
name: String::from(""),
Expand Down
Loading

0 comments on commit 4292faf

Please sign in to comment.