Skip to content

Commit 7a64e31

Browse files
authored
Merge pull request #56 from unsecretised/better-code-docs
Add documentation
2 parents 3be781e + dbcf038 commit 7a64e31

7 files changed

Lines changed: 174 additions & 71 deletions

File tree

src/app.rs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//! Main logic for the app
12
use crate::calculator::Expression;
23
use crate::clipboard::ClipBoardContentType;
34
use crate::commands::Function;
@@ -31,11 +32,20 @@ use std::cmp::min;
3132
use std::time::Duration;
3233
use std::{fs, thread};
3334

35+
/// The default window width
3436
pub const WINDOW_WIDTH: f32 = 500.;
37+
38+
/// The default window height
3539
pub const DEFAULT_WINDOW_HEIGHT: f32 = 65.;
3640

41+
/// The rustcast descriptor name to be put for all rustcast commands
3742
pub const RUSTCAST_DESC_NAME: &str = "RustCast";
3843

44+
/// The main app struct, that represents an "App"
45+
///
46+
/// This struct represents a command that rustcast can perform, providing the rustcast
47+
/// the data needed to search for the app, to display the app in search results, and to actually
48+
/// "run" the app.
3949
#[derive(Debug, Clone)]
4050
pub struct App {
4151
pub open_command: Function,
@@ -46,6 +56,7 @@ pub struct App {
4656
}
4757

4858
impl App {
59+
/// This returns the basic apps that rustcast has, such as quiting rustcast and opening preferences
4960
pub fn basic_apps() -> Vec<App> {
5061
vec![
5162
App {
@@ -65,6 +76,7 @@ impl App {
6576
]
6677
}
6778

79+
/// This renders the app into an iced element, allowing it to be displayed in the search results
6880
pub fn render(&self, theme: &crate::config::Theme) -> impl Into<iced::Element<'_, Message>> {
6981
let mut tile = Row::new().width(Fill).height(55);
7082

@@ -119,12 +131,14 @@ impl App {
119131
}
120132
}
121133

134+
/// The different pages that rustcast can have / has
122135
#[derive(Debug, Clone, PartialEq)]
123136
pub enum Page {
124137
Main,
125138
ClipboardHistory,
126139
}
127140

141+
/// The message type that iced uses for actions that can do something
128142
#[derive(Debug, Clone)]
129143
pub enum Message {
130144
OpenWindow,
@@ -140,6 +154,7 @@ pub enum Message {
140154
_Nothing,
141155
}
142156

157+
/// The window settings for rustcast
143158
pub fn default_settings() -> Settings {
144159
Settings {
145160
resizable: false,
@@ -156,6 +171,21 @@ pub fn default_settings() -> Settings {
156171
}
157172
}
158173

174+
/// This is the base window, and its a "Tile"
175+
/// Its fields are:
176+
/// - Theme ([`iced::Theme`])
177+
/// - Query (String)
178+
/// - Query Lowercase (String, but lowercase)
179+
/// - Previous Query Lowercase (String)
180+
/// - Results (Vec<[`App`]>) the results of the search
181+
/// - Options (Vec<[`App`]>) the options to search through
182+
/// - Visible (bool) whether the window is visible or not
183+
/// - Focused (bool) whether the window is focused or not
184+
/// - Frontmost ([`Option<Retained<NSRunningApplication>>`]) the frontmost application before the window was opened
185+
/// - Config ([`Config`]) the app's config
186+
/// - Open Hotkey ID (`u32`) the id of the hotkey that opens the window
187+
/// - Clipboard Content (`Vec<`[`ClipBoardContentType`]`>`) all of the cliboard contents
188+
/// - Page ([`Page`]) the current page of the window (main or clipboard history)
159189
#[derive(Debug, Clone)]
160190
pub struct Tile {
161191
theme: iced::Theme,
@@ -174,7 +204,7 @@ pub struct Tile {
174204
}
175205

176206
impl Tile {
177-
/// A base window
207+
/// Initialise the base window
178208
pub fn new(keybind_id: u32, config: &Config) -> (Self, Task<Message>) {
179209
let (id, open) = window::open(default_settings());
180210

@@ -227,6 +257,7 @@ impl Tile {
227257
)
228258
}
229259

260+
/// This handles the iced's updates, which have all the variants of [Message]
230261
pub fn update(&mut self, message: Message) -> Task<Message> {
231262
match message {
232263
Message::OpenWindow => {
@@ -412,6 +443,10 @@ impl Tile {
412443
}
413444
}
414445

446+
/// This is the view of the window. It handles the rendering of the window
447+
///
448+
/// The rendering of the window size (the resizing of the window) is handled by the
449+
/// [`Tile::update`] function.
415450
pub fn view(&self, wid: window::Id) -> Element<'_, Message> {
416451
if self.visible {
417452
let title_input = text_input(self.config.placeholder.as_str(), &self.query)
@@ -456,10 +491,20 @@ impl Tile {
456491
}
457492
}
458493

494+
/// This returns the theme of the window
459495
pub fn theme(&self, _: window::Id) -> Option<Theme> {
460496
Some(self.theme.clone())
461497
}
462498

499+
/// This handles the subscriptions of the window
500+
///
501+
/// The subscriptions are:
502+
/// - Hotkeys
503+
/// - Hot reloading
504+
/// - Clipboard history
505+
/// - Window close events
506+
/// - Keypresses (escape to close the window)
507+
/// - Window focus changes
463508
pub fn subscription(&self) -> Subscription<Message> {
464509
Subscription::batch([
465510
Subscription::run(handle_hotkeys),
@@ -492,6 +537,11 @@ impl Tile {
492537
])
493538
}
494539

540+
/// Handles the search query changed event.
541+
///
542+
/// This is separate from the `update` function because it has a decent amount of logic, and
543+
/// should be separated out to make it easier to test. This function is called by the `update`
544+
/// function to handle the search query changed event.
495545
pub fn handle_search_query_changed(&mut self) {
496546
let filter_vec: &Vec<App> = if self.query_lc.starts_with(&self.prev_query_lc) {
497547
self.prev_query_lc = self.query_lc.to_owned();
@@ -526,13 +576,15 @@ impl Tile {
526576
self.results = exact;
527577
}
528578

579+
/// Gets the frontmost application to focus later.
529580
pub fn capture_frontmost(&mut self) {
530581
use objc2_app_kit::NSWorkspace;
531582

532583
let ws = NSWorkspace::sharedWorkspace();
533584
self.frontmost = ws.frontmostApplication();
534585
}
535586

587+
/// Restores the frontmost application.
536588
#[allow(deprecated)]
537589
pub fn restore_frontmost(&mut self) {
538590
use objc2_app_kit::NSApplicationActivationOptions;
@@ -543,6 +595,7 @@ impl Tile {
543595
}
544596
}
545597

598+
/// This is the subscription function that handles hot reloading of the config
546599
fn handle_hot_reloading() -> impl futures::Stream<Item = Message> {
547600
stream::channel(100, async |mut output| {
548601
let content = fs::read_to_string(
@@ -563,6 +616,7 @@ fn handle_hot_reloading() -> impl futures::Stream<Item = Message> {
563616
})
564617
}
565618

619+
/// This is the subscription function that handles hotkeys for hiding / showing the window
566620
fn handle_hotkeys() -> impl futures::Stream<Item = Message> {
567621
stream::channel(100, async |mut output| {
568622
let receiver = GlobalHotKeyEvent::receiver();
@@ -577,6 +631,7 @@ fn handle_hotkeys() -> impl futures::Stream<Item = Message> {
577631
})
578632
}
579633

634+
/// This is the subscription function that handles the change in clipboard history
580635
fn handle_clipboard_history() -> impl futures::Stream<Item = Message> {
581636
stream::channel(100, async |mut output| {
582637
let mut clipboard = Clipboard::new().unwrap();

src/calculator.rs

Lines changed: 74 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
//! This handle the logic for the calculator in rustcast
2+
3+
/// A struct that represents an expression
14
#[derive(Debug, Clone, Copy)]
25
pub struct Expression {
36
pub first_num: f64,
47
pub operation: Operation,
58
pub second_num: f64,
69
}
710

11+
/// An enum that represents the different operations that can be performed on an expression
812
#[derive(Debug, Clone, Copy)]
913
pub enum Operation {
1014
Addition,
@@ -15,6 +19,7 @@ pub enum Operation {
1519
}
1620

1721
impl Expression {
22+
/// This evaluates the expression
1823
pub fn eval(&self) -> f64 {
1924
match self.operation {
2025
Operation::Addition => self.first_num + self.second_num,
@@ -25,79 +30,85 @@ impl Expression {
2530
}
2631
}
2732

33+
/// This parses an expression from a string (and is public)
34+
///
35+
/// This function is public because it is used in the `handle_search_query_changed` function,
36+
/// and the parse expression function, while doing the same thing, should not be public due to
37+
/// the function name, not portraying the intention of the function.
2838
pub fn from_str(s: &str) -> Option<Expression> {
29-
parse_expression(s)
30-
}
31-
}
32-
33-
fn parse_expression(s: &str) -> Option<Expression> {
34-
let s = s.trim();
35-
36-
// 1. Parse first (possibly signed) number with manual scan
37-
let (first_str, rest) = parse_signed_number_prefix(s)?;
38-
39-
// 2. Next non‑whitespace char must be the binary operator
40-
let rest = rest.trim_start();
41-
let (op_char, rest) = rest.chars().next().map(|c| (c, &rest[c.len_utf8()..]))?;
42-
43-
let operation = match op_char {
44-
'+' => Operation::Addition,
45-
'-' => Operation::Subtraction,
46-
'*' => Operation::Multiplication,
47-
'/' => Operation::Division,
48-
'^' => Operation::Power,
49-
_ => return None,
50-
};
51-
52-
// 3. The remainder should be the second (possibly signed) number
53-
let rest = rest.trim_start();
54-
let (second_str, tail) = parse_signed_number_prefix(rest)?;
55-
// Optionally ensure nothing but whitespace after second number:
56-
if !tail.trim().is_empty() {
57-
return None;
39+
Self::parse_expression(s)
5840
}
5941

60-
let first_num: f64 = first_str.parse().ok()?;
61-
let second_num: f64 = second_str.parse().ok()?;
42+
/// This is the function that parses an expression from a string
43+
fn parse_expression(s: &str) -> Option<Expression> {
44+
let s = s.trim();
45+
46+
// 1. Parse first (possibly signed) number with manual scan
47+
let (first_str, rest) = Self::parse_signed_number_prefix(s)?;
48+
49+
// 2. Next non‑whitespace char must be the binary operator
50+
let rest = rest.trim_start();
51+
let (op_char, rest) = rest.chars().next().map(|c| (c, &rest[c.len_utf8()..]))?;
52+
53+
let operation = match op_char {
54+
'+' => Operation::Addition,
55+
'-' => Operation::Subtraction,
56+
'*' => Operation::Multiplication,
57+
'/' => Operation::Division,
58+
'^' => Operation::Power,
59+
_ => return None,
60+
};
61+
62+
// 3. The remainder should be the second (possibly signed) number
63+
let rest = rest.trim_start();
64+
let (second_str, tail) = Self::parse_signed_number_prefix(rest)?;
65+
// Optionally ensure nothing but whitespace after second number:
66+
if !tail.trim().is_empty() {
67+
return None;
68+
}
6269

63-
Some(Expression {
64-
first_num,
65-
operation,
66-
second_num,
67-
})
68-
}
70+
let first_num: f64 = first_str.parse().ok()?;
71+
let second_num: f64 = second_str.parse().ok()?;
6972

70-
/// Returns (number_lexeme, remaining_slice) for a leading signed float.
71-
/// Very simple: `[+|-]?` + "anything until we hit whitespace or an operator".
72-
fn parse_signed_number_prefix(s: &str) -> Option<(&str, &str)> {
73-
let s = s.trim_start();
74-
if s.is_empty() {
75-
return None;
73+
Some(Expression {
74+
first_num,
75+
operation,
76+
second_num,
77+
})
7678
}
7779

78-
let mut chars = s.char_indices().peekable();
80+
/// Returns (number_lexeme, remaining_slice) for a leading signed float.
81+
/// Very simple: `[+|-]?` + "anything until we hit whitespace or an operator".
82+
fn parse_signed_number_prefix(s: &str) -> Option<(&str, &str)> {
83+
let s = s.trim_start();
84+
if s.is_empty() {
85+
return None;
86+
}
87+
88+
let mut chars = s.char_indices().peekable();
7989

80-
// Optional leading sign
81-
if let Some((_, c)) = chars.peek()
82-
&& (*c == '+' || *c == '-')
83-
{
84-
chars.next();
85-
}
90+
// Optional leading sign
91+
if let Some((_, c)) = chars.peek()
92+
&& (*c == '+' || *c == '-')
93+
{
94+
chars.next();
95+
}
8696

87-
// Now consume until we hit an operator or whitespace
88-
let mut end = 0;
89-
while let Some((idx, c)) = chars.peek().cloned() {
90-
if c.is_whitespace() || "+-*/^".contains(c) {
91-
break;
97+
// Now consume until we hit an operator or whitespace
98+
let mut end = 0;
99+
while let Some((idx, c)) = chars.peek().cloned() {
100+
if c.is_whitespace() || "+-*/^".contains(c) {
101+
break;
102+
}
103+
end = idx + c.len_utf8();
104+
chars.next();
92105
}
93-
end = idx + c.len_utf8();
94-
chars.next();
95-
}
96106

97-
if end == 0 {
98-
return None; // nothing that looks like a number
99-
}
107+
if end == 0 {
108+
return None; // nothing that looks like a number
109+
}
100110

101-
let (num, rest) = s.split_at(end);
102-
Some((num, rest))
111+
let (num, rest) = s.split_at(end);
112+
Some((num, rest))
113+
}
103114
}

src/clipboard.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//! This has all the logic regarding the cliboard history
12
use arboard::ImageData;
23
use iced::{
34
Length::Fill,
@@ -8,13 +9,15 @@ use iced::{
89

910
use crate::{app::Message, commands::Function};
1011

12+
/// The kinds of clipboard content that rustcast can handle and their contents
1113
#[derive(Debug, Clone)]
1214
pub enum ClipBoardContentType {
1315
Text(String),
1416
Image(ImageData<'static>),
1517
}
1618

1719
impl ClipBoardContentType {
20+
/// Returns the iced element for rendering the clipboard item
1821
pub fn render_clipboard_item(&self) -> impl Into<iced::Element<'_, Message>> {
1922
let mut tile = Row::new().width(Fill).height(55);
2023

@@ -58,6 +61,7 @@ impl ClipBoardContentType {
5861
}
5962

6063
impl PartialEq for ClipBoardContentType {
64+
/// Let cliboard items be comparable
6165
fn eq(&self, other: &Self) -> bool {
6266
if let Self::Text(a) = self
6367
&& let Self::Text(b) = other

0 commit comments

Comments
 (0)