Skip to content
Open
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
497 changes: 374 additions & 123 deletions Cargo.lock

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion ferritin-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ repository.workspace = true
license.workspace = true

[dependencies]
trillium-rustls = { version = "0.9.0", features = ["client"] }
trillium-rustls = { version = "0.9.0", features = [
"platform-verifier",
"client",
"tls12",
"ring",
], default-features = false }
trillium-smol = "0.4.2"
anyhow.workspace = true
cargo_metadata.workspace = true
Expand Down
54 changes: 47 additions & 7 deletions ferritin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ readme = "../README.md"
repository.workspace = true
license.workspace = true
include = [
"src/**/*",
"build.rs",
"assets/**/*.tmTheme",
"CHANGELOG.md",
"src/**/*",
"build.rs",
"assets/**/*.tmTheme",
"CHANGELOG.md",
"web/dist",
]

[[bin]]
Expand All @@ -31,19 +32,58 @@ pulldown-cmark = "0.13"
ratatui = "0.30"
regex = "1.12"
rustdoc-types.workspace = true
syntect = { version = "5.3", default-features = false, features = ["parsing", "default-syntaxes", "html", "plist-load", "yaml-load", "dump-load", "dump-create", "regex-onig"] }
syntect = { version = "5.3", default-features = false, features = [
"parsing",
"default-syntaxes",
"html",
"plist-load",
"yaml-load",
"dump-load",
"dump-create",
"regex-onig",
] }
terminal_size = "0.4"
thiserror = "2"
unicode-width = "0.2.2"
webbrowser = "1.1.0"
semver = "1.0.27"
percent-encoding = "2.3"
percent-encoding = "2.3.2"
mimalloc = "0.1.48"
trillium = { version = "0.2.20", optional = true }
trillium-router = { version = "0.4.1", optional = true }
trillium-smol = { version = "0.4.2", optional = true }
querystrong = { version = "0.4.0", optional = true }
serde = { version = "1.0.228", features = ["derive"], optional = true }
sonic-rs = { version = "0.5.7", optional = true }
trillium-logger = { version = "0.4.5", optional = true }
trillium-frontend = { version = "0.2.0", optional = true }

[build-dependencies]
syntect = { version = "5.3", default-features = false, features = ["parsing", "plist-load", "dump-load", "dump-create", "regex-onig"] }
syntect = { version = "5.3", default-features = false, features = [
"parsing",
"plist-load",
"dump-load",
"dump-create",
"regex-onig",
] }

[dev-dependencies]
serde = { version = "1.0.228", features = ["derive"] }
insta = { version = "1.46.3", features = ["filters"] }
paste = "1.0.15"
strip-ansi-escapes = "0.2.1"
trillium-testing = { version = "0.7.0", features = ["smol"] }

[features]
default = []
web = ["serve-json", "dep:trillium-frontend"]
dev = ["trillium-frontend/dev-proxy"]
serve-json = [
"dep:trillium",
"dep:trillium-router",
"dep:trillium-smol",
"dep:serde",
"dep:sonic-rs",
"dep:querystrong",
"dep:trillium-logger",
]
2 changes: 1 addition & 1 deletion ferritin/src/color_scheme.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::styled_string::SpanStyle;
use crate::document::SpanStyle;
use syntect::highlighting::{Color, Highlighter, Theme};
use syntect::parsing::{Scope, ScopeStack};

Expand Down
43 changes: 19 additions & 24 deletions ferritin/src/commands.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use crate::renderer::HistoryEntry;
use crate::document::Document;
use crate::request::Request;
use crate::styled_string::Document;
use std::fmt::Display;

mod get;
pub(crate) mod get;
pub(crate) mod list;
pub(crate) mod search;

Expand Down Expand Up @@ -39,6 +38,13 @@ pub(crate) enum Commands {

/// List available crates
List,

#[cfg(feature = "serve-json")]
/// Start JSON API server (uses HOST and PORT env vars, defaults to 127.0.0.1:8080)
Serve {
#[arg(short, long)]
open: bool,
},
}

impl Commands {
Expand Down Expand Up @@ -108,36 +114,25 @@ impl Commands {
}
}

pub fn execute<'a>(
self,
request: &'a Request,
) -> (Document<'a>, bool, Option<HistoryEntry<'a>>) {
pub fn execute<'a>(self, request: &'a Request) -> Document<'a> {
match self {
Commands::Get {
path,
source,
recursive,
} => {
let (doc, is_error, item_ref) = get::execute(request, &path, source, recursive);
let history_entry = item_ref.map(HistoryEntry::Item);
(doc, is_error, history_entry)
}
} => get::execute(request, &path, source, recursive),

Commands::Search {
query,
limit,
crate_,
} => {
let (doc, is_error) = search::execute(request, &query, limit, crate_.as_deref());
let history_entry = Some(HistoryEntry::Search {
query,
crate_name: crate_,
});
(doc, is_error, history_entry)
}
Commands::List => {
let (doc, is_error, default_crate) = list::execute(request);
let history_entry = Some(HistoryEntry::List { default_crate });
(doc, is_error, history_entry)
} => search::execute(request, &query, limit, crate_.as_deref()),

Commands::List => list::execute(request),

#[cfg(feature = "serve-json")]
Commands::Serve { .. } => {
unreachable!("Serve command should be handled before execute() is called")
}
}
}
Expand Down
24 changes: 14 additions & 10 deletions ferritin/src/commands/get.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use ferritin_common::DocRef;
use rustdoc_types::Item;
use std::time::Instant;

use crate::document::{Document, DocumentNode, ListItem, Span};
use crate::renderer::HistoryEntry;
use crate::request::Request;
use crate::styled_string::{Document, DocumentNode, ListItem, Span};

pub(crate) fn execute<'a>(
request: &'a Request,
path: &str,
source: bool,
recursive: bool,
) -> (Document<'a>, bool, Option<DocRef<'a, Item>>) {
) -> Document<'a> {
request
.format_context()
.set_include_source(source)
Expand All @@ -23,18 +23,22 @@ pub(crate) fn execute<'a>(
if let Some(name) = item.name() {
log::info!("Resolved {name}");
}
let start = std::time::Instant::now();
let start = Instant::now();
let doc_nodes = request.format_item(item);
let format_elapsed = start.elapsed();
if let Some(name) = item.name() {
log::debug!("⏱️ Formatted {name} in {:?}", format_elapsed);
}
(Document::from(doc_nodes), false, Some(item))
Document::from(doc_nodes)
.with_item(item)
.with_history_entry(HistoryEntry::Item(item))
}
None => {
let mut nodes = vec![DocumentNode::paragraph(vec![Span::plain(format!(
"Could not find '{path}'",
))])];
let mut nodes = vec![DocumentNode::paragraph(vec![
Span::plain("Could not find '"),
Span::emphasis(path.to_string()),
Span::plain("'"),
])];

if !suggestions.is_empty() {
nodes.push(DocumentNode::paragraph(vec![Span::plain("Did you mean:")]));
Expand All @@ -51,7 +55,7 @@ pub(crate) fn execute<'a>(
nodes.push(DocumentNode::List { items });
}

(Document::from(nodes), true, None)
Document::from(nodes).with_error()
}
}
}
7 changes: 4 additions & 3 deletions ferritin/src/commands/list.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::document::{Document, DocumentNode, HeadingLevel, ListItem, ShowWhen, Span};
use crate::renderer::HistoryEntry;
use crate::request::Request;
use crate::styled_string::{Document, DocumentNode, HeadingLevel, ListItem, ShowWhen, Span};

pub(crate) fn execute<'a>(request: &'a Request) -> (Document<'a>, bool, Option<&'a str>) {
pub(crate) fn execute<'a>(request: &'a Request) -> Document<'a> {
let mut nodes = vec![DocumentNode::Heading {
level: HeadingLevel::Title,
spans: vec![Span::plain("Available crates:")],
Expand Down Expand Up @@ -99,5 +100,5 @@ pub(crate) fn execute<'a>(request: &'a Request) -> (Document<'a>, bool, Option<&
});
}

(Document::from(nodes), false, default_crate)
Document::from(nodes).with_history_entry(HistoryEntry::List { default_crate })
}
21 changes: 12 additions & 9 deletions ferritin/src/commands/search.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use crate::document::{Document, DocumentNode, HeadingLevel, ListItem, Span, TruncationLevel};
use crate::renderer::HistoryEntry;
use crate::request::Request;
use crate::styled_string::{Document, DocumentNode, HeadingLevel, ListItem, Span, TruncationLevel};

pub(crate) fn execute<'a>(
request: &'a Request,
query: &str,
limit: usize,
crate_: Option<&str>,
) -> (Document<'a>, bool) {
) -> Document<'a> {
log::info!("Searching for {query}");

let crate_names: Vec<_> = match crate_ {
Expand Down Expand Up @@ -54,7 +55,7 @@ pub(crate) fn execute<'a>(
}
}

return (Document::from(nodes), true);
return Document::from(nodes).with_error();
}
};

Expand All @@ -64,7 +65,7 @@ pub(crate) fn execute<'a>(
if scored_results.is_empty() {
if query.is_empty() {
// Empty query - show search instructions
let doc = Document::from(vec![
return Document::from(vec![
DocumentNode::Heading {
level: HeadingLevel::Title,
spans: vec![Span::plain("Search")],
Expand All @@ -73,10 +74,9 @@ pub(crate) fn execute<'a>(
"Type to search. Press Tab to toggle between current crate and all crates.",
)]),
]);
return (doc, false);
} else {
// No matches for query
let error_doc = Document::from(vec![
return Document::from(vec![
DocumentNode::Heading {
level: HeadingLevel::Title,
spans: vec![Span::plain("No results")],
Expand All @@ -86,8 +86,8 @@ pub(crate) fn execute<'a>(
Span::plain(query.to_string()),
Span::plain("'"),
]),
]);
return (error_doc, false);
])
.with_error();
}
}

Expand Down Expand Up @@ -157,5 +157,8 @@ pub(crate) fn execute<'a>(

nodes.push(DocumentNode::List { items: list_items });

(Document::from(nodes), false)
Document::from(nodes).with_history_entry(HistoryEntry::Search {
query: query.into(),
crate_name: crate_.map(String::from),
})
}
Loading
Loading