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
89 changes: 86 additions & 3 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,84 @@
name: Release
name: Rust CI/CD

on:
push:
branches: [ main ]
branches: [main]
pull_request:
branches: [main, develop]

jobs:
fmt:
name: Format Check
runs-on: macos-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Rust
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt

- name: Run cargo fmt
run: cargo fmt --all -- --check

clippy:
name: Clippy Lints
runs-on: macos-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Rust
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: clippy

- name: Install Dependencies
run: |
brew install protobuf
brew install swift-protobuf

- name: Cache cargo registry
uses: actions/cache@v4
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}

- name: Cache cargo index
uses: actions/cache@v4
with:
path: ~/.cargo/git
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}

- name: Cache cargo build
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-build-target-clippy-${{ hashFiles('**/Cargo.lock') }}

- name: Run cargo clippy
run: cargo clippy --all-targets -- -D warnings

release:
name: Build and Release
runs-on: macos-latest
# Only run release on pushes to main (not on PRs)
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs: [fmt, clippy]
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # This ensures we get all git history
fetch-depth: 0 # This ensures we get all git history

- name: Setup Rust
uses: actions-rs/toolchain@v1
Expand All @@ -28,6 +93,24 @@ jobs:
brew install protobuf
brew install swift-protobuf

- name: Cache cargo registry
uses: actions/cache@v4
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}

- name: Cache cargo index
uses: actions/cache@v4
with:
path: ~/.cargo/git
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}

- name: Cache cargo build
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-build-target-release-${{ hashFiles('**/Cargo.lock') }}

- name: Get Version
id: get_version
run: |
Expand Down
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,40 @@ To resolve the problem, run the following command in Terminal:
```
xattr -d com.apple.quarantine ~/Downloads/FastForward.dmg
```

## Development

### Prerequisites
- Rust (stable toolchain)
- Xcode Command Line Tools
- protobuf: `brew install protobuf`
- swift-protobuf: `brew install swift-protobuf`

### Building from Source

```bash
# Clone the repository
git clone https://github.com/yourusername/fast-forward.git
cd fast-forward

# Build in debug mode
cargo build

# Build in release mode
cargo build --release

# Run the application
cargo run
```

### Code Quality

This project uses `cargo fmt` and `cargo clippy` to maintain code quality.

```bash
# Format code
cargo fmt --all

# Run linter
cargo clippy --all-targets -- -D warnings
```
44 changes: 30 additions & 14 deletions src/applications.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ use log::error;
use objc2::rc::Retained;
use objc2_app_kit::{NSApplicationActivationOptions, NSRunningApplication, NSWorkspace};

use crate::ui::input::SearchQuery;
use crate::window::Window;
use crate::socket_message::App as Application;
use crate::ui::input::SearchQuery;
use crate::ui::list::List;
use crate::window::Window;

#[derive(Debug, Clone)]
pub struct Applications {
Expand All @@ -22,7 +22,7 @@ impl Default for Applications {
Self {
list: Vec::new(),
index: 0,
loading: true
loading: true,
}
}
}
Expand All @@ -31,7 +31,7 @@ impl Default for Applications {
pub enum ActionType {
Activate,
Hide,
Quit
Quit,
}

#[derive(Debug, Clone, Copy)]
Expand All @@ -51,7 +51,7 @@ impl Applications {
cx.set_global(Self {
list,
index: 0,
loading: false
loading: false,
});
}

Expand All @@ -66,12 +66,19 @@ impl Applications {
cx.set_global(applications);
}

pub fn update_list_entry(cx: &mut App, app: Option<&Application>, index_type: Option<IndexType>, reset: bool) {
pub fn update_list_entry(
cx: &mut App,
app: Option<&Application>,
index_type: Option<IndexType>,
reset: bool,
) {
let applications = cx.global::<Applications>();
let mut applications = applications.clone();

if let Some(app) = app {
if let Some(existing_app_index) = applications.list.iter().position(|a| a.name == app.name) {
if let Some(existing_app_index) =
applications.list.iter().position(|a| a.name == app.name)
{
if index_type.is_some() {
applications.list.remove(existing_app_index);
} else {
Expand All @@ -80,7 +87,8 @@ impl Applications {
}

if let Some(index_type) = index_type {
let target_index = Self::get_index_from_type(&applications.list, applications.index, index_type);
let target_index =
Self::get_index_from_type(&applications.list, applications.index, index_type);
applications.list.insert(target_index, app.clone());
}
}
Expand All @@ -90,7 +98,9 @@ impl Applications {
// Reset the active index and search query.
if reset {
Self::update_active_index(cx, IndexType::Start);
cx.set_global(SearchQuery { value: String::new() });
cx.set_global(SearchQuery {
value: String::new(),
});
}
}

Expand All @@ -113,14 +123,14 @@ impl Applications {
unsafe {
native_app.activateWithOptions(NSApplicationActivationOptions::empty());
}
},
}
ActionType::Hide => {
Self::update_list_entry(cx, Some(app), Some(IndexType::End), true);

unsafe {
native_app.hide();
}
},
}
ActionType::Quit => {
Self::update_list_entry(cx, Some(app), None, true);

Expand All @@ -142,7 +152,11 @@ impl Applications {
}
}

fn get_index_from_type(list: &[Application], current_index: usize, index_type: IndexType) -> usize {
fn get_index_from_type(
list: &[Application],
current_index: usize,
index_type: IndexType,
) -> usize {
match index_type {
IndexType::Start => 0,
IndexType::End => list.len(),
Expand All @@ -153,14 +167,16 @@ impl Applications {
} else {
current_index - 1
}
},
}
}
}

fn get_running_app_instance(app: &Application) -> Option<Retained<NSRunningApplication>> {
unsafe {
let running_applications = NSWorkspace::sharedWorkspace().runningApplications();
running_applications.iter().find(|item| item.localizedName().unwrap().to_string() == app.name)
running_applications
.iter()
.find(|item| item.localizedName().unwrap().to_string() == app.name)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/assets.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::{fs, path::PathBuf};
use anyhow::anyhow;
use std::{fs, path::PathBuf};

use gpui::{AssetSource, Result, SharedString};
use rust_embed::RustEmbed;
Expand Down
45 changes: 33 additions & 12 deletions src/commander/handlers.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
use std::sync::atomic::{AtomicBool, Ordering};
use gpui::{AsyncApp, Result};
use std::sync::atomic::{AtomicBool, Ordering};

use super::events::{EventType, HotkeyEvent, TrayEvent};
use crate::socket_message::socket_message::Event as SocketEvent;
use crate::{
applications::{ActionType, Applications, IndexType},
config::Config,
window::Window,
};
use super::events::{EventType, HotkeyEvent, TrayEvent};
use crate::socket_message::socket_message::Event as SocketEvent;

static ESCAPE_PRESSED: AtomicBool = AtomicBool::new(false);
static SPACE_PRESSED: AtomicBool = AtomicBool::new(false);

pub(super) fn handle_event(cx: &AsyncApp, event: EventType) -> Result<(), Box<dyn std::error::Error>> {
pub(super) fn handle_event(
cx: &AsyncApp,
event: EventType,
) -> Result<(), Box<dyn std::error::Error>> {
match event {
EventType::HotkeyEvent(event) => handle_hotkey_event(cx, event),
EventType::TrayEvent(event) => handle_tray_event(cx, event),
EventType::SocketEvent(event) => handle_socket_event(cx, event),
}
}

fn handle_hotkey_event(cx: &AsyncApp, event: HotkeyEvent) -> Result<(), Box<dyn std::error::Error>> {
fn handle_hotkey_event(
cx: &AsyncApp,
event: HotkeyEvent,
) -> Result<(), Box<dyn std::error::Error>> {
match event {
HotkeyEvent::ShowWindow(offset) => {
cx.update(|cx| {
Window::show(cx, offset)
})?;
cx.update(|cx| Window::show(cx, offset))?;
}
HotkeyEvent::HideWindow => {
cx.update(|cx| {
Expand Down Expand Up @@ -53,7 +57,7 @@ fn handle_tray_event(cx: &AsyncApp, event: TrayEvent) -> Result<(), Box<dyn std:
.arg("TextEdit")
.arg(Config::config_path()?)
.spawn()?;
},
}
TrayEvent::About => {
cx.update(|cx| cx.open_url("https://github.com/gaauwe/fast-forward"))?;
}
Expand All @@ -64,19 +68,36 @@ fn handle_tray_event(cx: &AsyncApp, event: TrayEvent) -> Result<(), Box<dyn std:
Ok(())
}

fn handle_socket_event(cx: &AsyncApp, event: SocketEvent) -> Result<(), Box<dyn std::error::Error>> {
fn handle_socket_event(
cx: &AsyncApp,
event: SocketEvent,
) -> Result<(), Box<dyn std::error::Error>> {
match event {
SocketEvent::List(event) => {
cx.update(|cx| Applications::update_list(cx, event.apps.clone()))?;
}
SocketEvent::Launch(event) => {
cx.update(|cx| Applications::update_list_entry(cx, event.app.as_ref(), Some(IndexType::Start), false))?;
cx.update(|cx| {
Applications::update_list_entry(
cx,
event.app.as_ref(),
Some(IndexType::Start),
false,
)
})?;
}
SocketEvent::Close(event) => {
cx.update(|cx| Applications::update_list_entry(cx, event.app.as_ref(), None, false))?;
}
SocketEvent::Activate(event) => {
cx.update(|cx| Applications::update_list_entry(cx, event.app.as_ref(), Some(IndexType::Start), false))?;
cx.update(|cx| {
Applications::update_list_entry(
cx,
event.app.as_ref(),
Some(IndexType::Start),
false,
)
})?;
}
}
Ok(())
Expand Down
3 changes: 2 additions & 1 deletion src/commander/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ impl Commander {
.timer(Duration::from_millis(50))
.await;
}
}).detach();
})
.detach();

cx.set_global::<Commander>(Self { tx });
}
Expand Down
Loading
Loading