Initial implementation

This commit is contained in:
2023-09-26 17:59:12 -05:00
parent b51c0c5274
commit 35e55baab1
6 changed files with 1433 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/target

1278
Cargo.lock generated Normal file
View File

File diff suppressed because it is too large Load Diff

15
Cargo.toml Normal file
View File

@@ -0,0 +1,15 @@
[package]
name = "find-syntax"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = { version = "4.4.5", features = ["derive"] }
env_logger = "0.10.0"
log = "0.4.20"
path-clean = "1.0.1"
regex = "1.9.5"
reqwest = { version = "0.11.20", features = ["blocking", "json"] }
serde = { version = "1.0.188", features = ["derive"] }

26
src/languages.rs Normal file
View File

@@ -0,0 +1,26 @@
use regex::Regex;
use std::collections::HashSet;
use crate::markdown::get_client;
const LANGUAGES_YML_URL: &str =
"https://raw.githubusercontent.com/github-linguist/linguist/master/lib/linguist/languages.yml";
const EXTENSION_PATTERN: &str = r#"(?m)^\s*extensions:\s+-\s+"\.([\w\d]+)""#;
// Find all lines that look like `- ".ext"` and extract the extension. Each extension should be added to the set returned.
pub fn get_languages() -> Result<HashSet<String>, Box<dyn std::error::Error>> {
let client = get_client();
let mut languages = HashSet::new();
let languages_yml = client.get(LANGUAGES_YML_URL).send()?.text()?;
let pattern = Regex::new(EXTENSION_PATTERN)?;
pattern
.captures_iter(languages_yml.as_str())
.for_each(|captures| {
let extension = captures.get(1).unwrap().as_str();
languages.insert(extension.to_string());
});
Ok(languages)
}

76
src/main.rs Normal file
View File

@@ -0,0 +1,76 @@
use std::{path::{Path, PathBuf}, io, env, fs::create_dir_all};
use clap::Parser;
use log::{debug, error, info, trace, warn};
use path_clean::PathClean;
mod languages;
mod markdown;
pub fn absolute_path(path: impl AsRef<Path>) -> PathBuf {
let path = path.as_ref();
let absolute_path = if path.is_absolute() {
path.to_path_buf()
} else {
env::current_dir().expect("").join(path)
}.clean();
absolute_path
}
/// Simple program to greet a person
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
#[arg()]
file: String,
#[arg(short, long, default_value = "./.cache")]
cache_dir: String,
}
fn main() {
let args = Args::parse();
env_logger::init();
let cache_dir = absolute_path(Path::new(&args.cache_dir));
debug!("Cache directory: {}", cache_dir.display());
if !cache_dir.exists() {
debug!("Cache directory does not exist; creating...");
create_dir_all(cache_dir).unwrap();
}
// TODO: Given an input file argument, read the file.
let file = absolute_path(Path::new(&args.file));
debug!("File: {}", file.display());
if !file.exists() {
error!("File does not exist: {}", file.display());
return;
}
// Function to generate a formatted markdown document of the file.
let get_formatted_file = |language: &str, content: &str| -> String {
format!("```{language}\n{content}\n```")
};
// Determine all available languages for highlighting abilities.
let languages = languages::get_languages().unwrap();
debug!("{} unique languages found.", languages.len());
// TODO: Begin querying GitHub Markdown API
languages.iter().for_each(|language| {
let markdown = markdown::get_markdown(&get_formatted_file(language, "Hello, world!")).unwrap();
debug!("Markdown: {}", markdown);
});
// TODO: Cache responses locally
// TODO: Determine complexity & level of colorization for each response
// TODO: Provide a report of what syntax highlighting works best
}

37
src/markdown.rs Normal file
View File

@@ -0,0 +1,37 @@
use serde::{Serialize, Deserialize};
use reqwest::blocking::Client;
const MARKDOWN_API_ENDPOINT: &str = "https://api.github.com/markdown";
#[derive(Debug, Serialize, Deserialize)]
struct MarkdownRequest {
text: String,
#[serde(skip_serializing_if = "String::is_empty")]
mode: String,
#[serde(skip_serializing_if = "String::is_empty")]
context: String,
}
pub fn get_client() -> Client {
let client = Client::builder()
.user_agent("xevion-find-syntax")
.build()
.unwrap();
client
}
pub fn get_markdown(text: &str) -> Result<String, Box<dyn std::error::Error>> {
let client = get_client();
let request = MarkdownRequest {
text: text.to_string(),
mode: "".to_string(),
context: "".to_string()
};
let response = client.post(MARKDOWN_API_ENDPOINT).json(&request).send()?;
let markdown = response.text()?;
Ok(markdown)
}