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
4 changes: 2 additions & 2 deletions .env
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
DATABASE_FILENAME=shortcuts.db
DATABASE_FILENAME=shortcut.db
DATABASE_URL=sqlite://${DATABASE_FILENAME}?mode=rwc
PORT=3000
PORT=8035
UI_URL=http://localhost:${PORT}
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ jobs:

- name: Set-up Database
env:
DATABASE_URL: "sqlite://shortcuts.db?mode=rwc"
DATABASE_URL: "sqlite://shortcut.db?mode=rwc"
run: |
sqlx db create
sqlx migrate run --source ./migrations
Expand All @@ -105,5 +105,5 @@ jobs:
nohup cargo run > server.log 2>&1 &
echo "Waiting for server to start..."
# Wait up to 30 seconds for healthcheck
timeout 30 bash -c 'until curl -fs http://localhost:3000/healthcheck; do echo "Waiting for server..."; sleep 2; done'
timeout 30 bash -c 'until curl -fs http://localhost:8035/healthcheck; do echo "Waiting for server..."; sleep 2; done'
echo "Server is up and running."
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ SQLite-trunk*
*.db
*.db-shm
*.db-wal
ui/assets/main.css
ui/assets/main.css
build/*_installer.iss
11 changes: 7 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
[package]
name = "shortcuts"
name = "shortcut"
version = "1.0.3"
edition = "2021"
include = ["ui/", "migrations/"]
build = "build/build.rs"

[dependencies]
axum = { version = "0.8.1", features = ["macros"] }
axum = { version = "0.8.4", features = ["macros"] }
dotenv = "0.15"
serde = { version = "1.0.219", features = ["derive"] }
sqlx = { version= "0.8.5", features=["sqlite"] }
state = "0.6.0"
tera = { version = "1.20", default-features = false}
tera-hot-reload = { version = "0.2.4" }
tokio = { version = "1.39.2", features = ["full"] }
tower-http = { version = "0.6.1", features = ["full"] }
tokio = { version = "1.45.0", features = ["full"] }
tower-http = { version = "0.6.4", features = ["full"] }
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
tracing = "0.1.40"
thiserror = "2.0.12"
Expand All @@ -21,3 +23,4 @@ sqlx-cli = "0.8.5"
rust-fuzzy-search = "0.1.1"
lazy_static = "1.5.0"
mockall = "0.13.1"
auto-launch = "0.5.0"
23 changes: 23 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,26 @@ tailwind-watch:

server-watch:
RUST_LOG=info cargo watch -x run

build-windows:
echo "🦀 Building Rust project..."
rustup target add x86_64-pc-windows-gnu
cargo build --release --target x86_64-pc-windows-gnu

# Linux commands (without inno):
VERSION=$(grep '^version' Cargo.toml | head -n1 | cut -d '"' -f2)
sed "s/{#AppVersion}/$VERSION/" build/windows_template.iss > build/windows_installer.iss

# Window commands:
# $versionLine = Get-Content Cargo.toml | Where-Object { $_ -match '^version\s*=' } | Select-Object -First 1
# $version = $versionLine -replace '^version\s*=\s*"(.*)"', '$1'
# (Get-Content build\windows_template.iss) -replace '\{#AppVersion\}', $version | Set-Content build\windows_installer.iss
# & "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" ".\build\windows_installer.iss"

echo "✅ Done!"

build-mac:
sudo apt install -y libzstd-dev pkg-config build-essential

cargo build --release --target x86_64-apple-darwin
# cargo build --release --target x86_64-unknown-linux-gnu
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
[![CI][s0]][l0] [![UNSAFE][s3]][l3] [![dep_status][s7]][l7]
</h1>

[s0]: https://github.com/AlexTrebs/Shortcuts/workflows/CI/badge.svg
[l0]: https://github.com/AlexTrebs/Shortcuts/actions
[s0]: https://github.com/AlexTrebs/Shortcut/workflows/CI/badge.svg
[l0]: https://github.com/AlexTrebs/Shortcut/actions
[s3]: https://img.shields.io/badge/unsafe-forbidden-success.svg
[l3]: https://github.com/rust-secure-code/safety-dance/
[s7]: https://deps.rs/repo/github/AlexTrebs/Shortcuts/status.svg
[l7]: https://deps.rs/repo/github/AlexTrebs/Shortcuts
[s7]: https://deps.rs/repo/github/AlexTrebs/Shortcut/status.svg
[l7]: https://deps.rs/repo/github/AlexTrebs/Shortcut

<h5 align="center">A fast, simple, browser shortcut tool.</h1>

![](docs/images/shortcuts_demo.gif)
![](docs/images/shortcut_demo.gif)

## <a name="table-of-contents"></a> Table of Contents

Expand Down Expand Up @@ -104,34 +104,34 @@ Following this you will need to set up a shortcut for your search bar. Given you
1. Go to chrome://settings/search.
2. Click "Manage search engines and site search".
3. Click "Add" next to "Site search".
4. Fill the url to be `http://localhost:3000/api/get?keyword=%s`
4. Fill the url to be `http://localhost:8035/api/get?keyword=%s`
5. Fill out the rest of the details and save.

#### <b><u>Mozilla Firefox:</u></b>
1. Go to about:preferences#search.
2. Click "Search Shortcuts".
2. Click "Search Shortcut".
3. Click "Add".
4. Fill the url to be `http://localhost:3000/api/get?keyword=%s`
4. Fill the url to be `http://localhost:8035/api/get?keyword=%s`
5. Fill out the rest of the details and save.

#### <b><u>Microsoft Edge:</u></b>
1. Go to edge://settings/searchEngines?search=address.
2. Click "Add" next to "Site search".
3. Fill the url to be `http://localhost:3000/api/get?keyword=%s`
3. Fill the url to be `http://localhost:8035/api/get?keyword=%s`
4. Fill out the rest of the details and save.

#### <b><u>Brave:</u></b>
1. Go to brave://settings/search.
2. Click "Manage search engines and site search".
3. Click "Add" next to "Site search".
4. Fill the url to be `http://localhost:3000/api/get?keyword=%s`
4. Fill the url to be `http://localhost:8035/api/get?keyword=%s`
5. Fill out the rest of the details and save.

#### <b><u>Vivaldi:</u></b>
1. Go to vivaldi://settings/search.
2. Click "Search Engines".
3. Click "Add" next to "Site search".
4. Fill the url to be `http://localhost:3000/api/get?keyword=%s`
4. Fill the url to be `http://localhost:8035/api/get?keyword=%s`
5. Fill out the rest of the details and save.

## 5. <a name="arch"></a> Architecture <small><sup>[Top ▲](#table-of-contents)</sup></small>
Expand Down Expand Up @@ -201,7 +201,7 @@ All the config is kept within the `.env` file.
The default is:

```sh
DATABASE_FILENAME=shortcuts.db
DATABASE_FILENAME=shortcut.db
DATABASE_URL=sqlite://${DATABASE_FILENAME}?mode=rwc
PORT=3000
UI_URL=http://localhost:${PORT}
Expand Down
1 change: 1 addition & 0 deletions app_icon.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
IDI_ICON1 ICON "docs/images/icon.ico"
Binary file added app_icon.res
Binary file not shown.
Binary file added build/ShortcutInstaller.exe
Binary file not shown.
80 changes: 80 additions & 0 deletions build/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

fn main() {
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let profile = env::var("PROFILE").unwrap();
let target = env::var("TARGET").unwrap();

let ui_dest = PathBuf::from(manifest_dir)
.join("target")
.join(target)
.join(profile)
.join("ui");
let ui_src = Path::new("ui");
println!("us_dest: {:?}", ui_dest.to_str());

println!("cargo:info=Copying UI folder to build output...");

if !ui_src.exists() {
panic!("cargo:error=UI directory does not exist! Make sure it is in the project root.");
}

fs::create_dir_all(&ui_dest).expect("cargo:error=Failed to create UI directory.");

copy_dir(ui_src, &ui_dest).expect("cargo:error=Failed to copy UI files.");

println!("cargo:info=UI folder copied successfully!");

// Apply OS-specific setup after copying files
apply_os_specific_setup(&ui_dest);
}

/// Recursively copies all files and subdirectories
fn copy_dir(src: &Path, dest: &Path) -> std::io::Result<()> {
for entry in fs::read_dir(src)? {
let entry = entry?;
let path = entry.path();
let dest_path = dest.join(entry.file_name());

if path.is_dir() {
fs::create_dir_all(&dest_path)?;
copy_dir(&path, &dest_path)?;
} else {
fs::copy(&path, &dest_path)?;
}
}
Ok(())
}

/// OS-specific setup function
fn apply_os_specific_setup(ui_dest: &Path) {
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();

match target_os.as_str() {
"windows" => {
println!("cargo:rerun-if-changed=app_icon.rc");
println!("cargo:rustc-link-arg=app_icon.res");
println!("cargo:info=Applying Windows-specific setup...");
let _ = std::process::Command::new("attrib")
.args(["+R", ui_dest.to_str().unwrap()])
.status();
}
"linux" => {
println!("cargo:info=Applying Linux-specific setup...");
let _ = std::process::Command::new("chmod")
.args(["-R", "755", ui_dest.to_str().unwrap()])
.status();
}
"macos" => {
println!("cargo:info=Applying macOS-specific setup...");
let _ = std::process::Command::new("chmod")
.args(["-R", "755", ui_dest.to_str().unwrap()])
.status();
}
_ => {
println!("cargo:error=Unknown target OS: {}", target_os);
}
}
}
17 changes: 17 additions & 0 deletions build/windows_template.iss
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[Setup]
AppName=Shortcut
AppVersion={#AppVersion}
DefaultDirName={pf}\Shortcut
OutputDir=.
OutputBaseFilename=ShortcutInstaller
Compression=lzma
SolidCompression=yes
SetupIconFile=docs\icon.ico

[Files]
Source: "target/x86_64-pc-windows-gnu/release/shortcut.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "../target/x86_64-pc-windows-gnu/release/ui/*"; DestDir: "{app}/ui/"; Flags: ignoreversion recursesubdirs
Source: "../.env"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs

[Icons]
Name: "{group}\Shortcut"; Filename: "{app}\shortcut.exe"
Binary file added docs/images/icon.ico
Binary file not shown.
Binary file added docs/images/small_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
-- Load the spellfix1 extension
-- SELECT load_extension('extensions/spellfix1');

CREATE TABLE IF NOT EXISTS shortcuts (
CREATE TABLE IF NOT EXISTS shortcut (
id INTEGER UNIQUE,
created INTEGER NOT NULL,
updated INTEGER NOT NULL,
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "shortcuts",
"name": "shortcut",
"version": "1.0.3",
"description": "",
"main": "index.js",
Expand Down
9 changes: 9 additions & 0 deletions server.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
nohup: ignoring input
Compiling shortcut v1.0.3 (/root/workplace/shortcut)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 5.93s
Running `target/debug/shortcut`
2025-06-17T21:30:28.116518Z  INFO shortcut: listening on 0.0.0.0:8035

thread 'main' panicked at /root/workplace/shortcut/src/lib.rs:96:50:
called `Result::unwrap()` on an `Err` value: Os { code: 98, kind: AddrInUse, message: "Address already in use" }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
6 changes: 3 additions & 3 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use thiserror::Error;
pub enum ShortcutError {
#[error("shortcut not found.")]
NotFound,
#[error("Failed to get shortcuts.")]
#[error("Failed to get shortcut.")]
FailedToGet,
#[error("Failed to create shortcut. Please try again.")]
FailedToCreate,
Expand All @@ -14,8 +14,8 @@ pub enum ShortcutError {
FailedToUpdate,
#[error("Failed to find match for keyword, would you like to create one?.")]
NoMatches,
#[error("Failed to search shortcuts.")]
#[error("Failed to search shortcut.")]
FailedToSearch,
#[error("Failed to delete shortcuts.")]
#[error("Failed to delete shortcut.")]
FailedToDelete
}
2 changes: 1 addition & 1 deletion src/macros/renderable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ macro_rules! impl_renderable {
($($t:ty),*) => {
$(impl Renderable for $t {
fn get_html(&self, tera: Tera) -> Html<String> {
Html(self.render(tera))
Html(self.render(&tera))
}
})*
};
Expand Down
31 changes: 30 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,35 @@
use shortcuts::run;
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use shortcut::run;
use auto_launch::AutoLaunch;
use std::env;

#[tokio::main]
async fn main() {
let binding = env::current_exe().unwrap();
let app_path = binding.to_str().unwrap();
let app_name = "shortcut";
let args = &["--minimized"];

#[cfg(target_os = "windows")] {
let auto = AutoLaunch::new(app_name, app_path, args);
setup_auto_launch(auto);
}

#[cfg(target_os = "macos")] {
let auto = AutoLaunch::new(app_name, app_path, false, args);
setup_auto_launch(auto);
}

#[cfg(target_os = "linux")] {
let auto = AutoLaunch::new(app_name, app_path, args);
setup_auto_launch(auto);
}

run().await;
}

fn setup_auto_launch(auto: AutoLaunch) {
// enable the auto launch
let _ =auto.enable().is_ok();
auto.is_enabled().unwrap();
}
Loading
Loading