欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

利用rust編一個靜態(tài)博客工具

 更新時間:2023年12月07日 14:05:27   作者:tommy_1  
這篇文章主要為大家詳細介紹了如何利用rust編一個靜態(tài)博客工具,這個靜態(tài)博客的工具主要是把md文檔轉(zhuǎn)為html靜態(tài)網(wǎng)站/博客,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

這個靜態(tài)博客的工具主要是把md文檔轉(zhuǎn)為html靜態(tài)網(wǎng)站/博客。github鏈接github.com/maochunguang/rust-md-site-tool

首先說明md文檔轉(zhuǎn)為靜態(tài)網(wǎng)站/博客的原理,就是先做一個目錄文檔,叫做summary.md,然后其他文檔都會鏈接到這個目錄文檔里。當把md文檔轉(zhuǎn)為html時,需要對鏈接進行處理,保證鏈接可以正常跳轉(zhuǎn),這樣就完成了一個簡單的md轉(zhuǎn)靜態(tài)博客工具。

第一步,設(shè)計博客工具

目錄和樣式設(shè)計

這個簡易的博客/站點工具主要是模仿gitbook,可以認為是gitbook的簡易版。頁面布局也是gitbook一樣,左邊是目錄,右邊是內(nèi)容。

首先需要定義一個博客的靜態(tài)目錄結(jié)構(gòu),如下圖所示:

  • docs目錄是所有md文檔源文件;
  • static目錄是所有靜態(tài)文件的存放目錄,比如js,css,image文件;
  • md_config.toml是全局配置文件,
  • summary.md是全局站點的目錄;
  • index.md是全局首頁內(nèi)容

├── docs
│   ├── chapter1
│   │   ├── chapter1.html
│   │   ├── chapter1.md
│   ├── chapter2
│   │   ├── chapter2.html
│   │   ├── chapter2.md
│   ├── index.md
│   └── summary.md
├── md_config.toml
└── static
    ├── css
    │   └── style.css
    ├── images
    └── js

summary.md格式如下:

* [章節(jié)1](chapter1/chapter1.md)
  * [小節(jié)1.1](chapter1/section1.1.md)
  * [小節(jié)1.2](chapter1/section1.2.md)
* [章節(jié)2](chapter2/chapter2.md)
  * [小節(jié)2.1](chapter2/section2.1.md)
  * [小節(jié)2.2](chapter2/section2.2.md)

配置文件結(jié)構(gòu)如下:

title = "My Blog"
author = "Your Name"
description = "This is my blog."
port = 9900
static_dir = "static"
md_source_dir = "docs"
output_dir = ".site"
default_css_header = "<link rel=\"stylesheet\" href=\"./css/style.css\">"
default_code_header = "<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/styles/default.min.css\"><script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/highlight.min.js\"></script>"
default_code_plugin = "<script>hljs.highlightAll();</script>"

功能實現(xiàn)和設(shè)計

本質(zhì)上是一個命令行工具,依賴clap=4.4.0來創(chuàng)建,第一版支持三個命令:

  • init,初始化一些目錄和配置文件
  • build,構(gòu)建所有的文件,轉(zhuǎn)為html到指定的輸出目錄
  • run,本地運行,在本地預(yù)覽

由于要實現(xiàn)md文件轉(zhuǎn)為html,需要借助依賴pulldown-cmark = "0.9"。

第二步,創(chuàng)建三個命令

創(chuàng)建main.js,把三個命令寫出來:

fn main() {
    let matches = Command::new("rust-md-blog-tool")
        .version("1.0")
        .author("Your Name")
        .about("A simple static site generator")
        .subcommand(Command::new("init")
            .about("Initializes the blog with default configuration"))
        .subcommand(Command::new("build")
            .about("Builds the static site from markdown files"))
        .subcommand(Command::new("run")
            .about("Runs a local server to view the blog"))
        .get_matches();

    match matches.subcommand() {
        Some(("init", _)) => init_lib::init_command(),
        Some(("build", _)) => build_lib::build_command(),
        Some(("run", _)) => server_lib::run_command(),
        _ => println!("Invalid command or no command provided"),
    }
}

第三步,實現(xiàn)init命令

init命令就是創(chuàng)建一個默認的配置文件,以及六個目錄和一個css文件。 核心代碼如下:

  • config_content是默認的配置文件內(nèi)容,可以自定義字符串或者使用模板文件;
  • get_style_content是默認的css文件,可以自定義字符串或者使用模板文件;
    let _ = File::create("md_config.toml").and_then(|mut file| file.write_all(config_content.as_bytes()));

    // 創(chuàng)建所需的目錄
    let _ = fs::create_dir_all("docs").map(|_| println!("created 'docs' Success"));
    let _ = fs::create_dir_all(".site").map(|_| println!("created '.site' Success"));
    let _ = fs::create_dir_all("static").map(|_| println!("created 'static' Success"));
    let _ = fs::create_dir_all("static/js").map(|_| println!("created 'static/js' Success"));
    let _ = fs::create_dir_all("static/css").map(|_| println!("created 'static/css' Success"));
    let _ = fs::create_dir_all("static/images").map(|_| println!("created 'static/images' Success"));
    let _ = File::create("static/css/style.css").and_then(|mut file| file.write_all(get_style_content().as_bytes())); 
    println!("Blog initialized with default configuration.");

第四步,實現(xiàn)build命令

構(gòu)建所有的md文件流程也很簡單:

核心代碼如下:

pub fn build_command() {
    // ... 讀取配置文件和設(shè)置目錄 ...
    let config = fs::read_to_string("md_config.toml").expect("Unable to read config file");
    let parsed_config = config.parse::<Value>().expect("Unable to parse config");
    let source_dir =  parsed_config.get("md_source_dir").and_then(Value::as_str).unwrap_or("docs");
    // .....
    println!("load config source_dir :{}, output_dir:{}", source_dir, output_dir);
    let md_source_dir = Path::new(source_dir);
    let summary_path =format!("{}{}", source_dir, "/summary.md");

 
    // 解析 summary.md 并構(gòu)建目錄HTML
    let toc_html = build_toc_content(summary_path.clone());
    
    // 解析每個.md文件 轉(zhuǎn)為HTML
    let md_files = read_dir_recursive(md_source_dir).expect("read md dir failed");

    // 為每個Markdown文件生成HTML頁面
    for entry in md_files {
        let path = entry;
        if path.ends_with("summary.md"){
            continue;
        }
        let output_file_path = transform_path(&path, source_dir, output_dir);
        if path.extension().and_then(|s| s.to_str()) == Some("md") {
            let mut md_content = String::new();
            File::open(&path).and_then(|mut file| file.read_to_string(&mut md_content)).expect("Failed to read Markdown file");
            let parser = Parser::new(&md_content);
            let mut html_content = String::new();
            html::push_html(&mut html_content, parser);
            let _ = html_content.replace(".md", ".html");
            let output_file = output_file_path.with_extension("html");
            println!("output file:{}", output_file.as_path().display());
            let mut full_html;
            // 處理index頁面邏輯
            full_html = format!("<html><head></head><body><div class=\"toc\">{}</div><div class=\"content\">{}</div></body></html>", toc_html, html_content);
            full_html = append_html(&full_html, "</head>", &[default_css_header, default_code_header]);
            // 增加highlight.js處理代碼塊
            full_html = append_html(&full_html, "</body>", &[default_code_plugin]);
            // 處理相對路徑
            if contains_sub_dir(&output_file, output_dir){
                full_html = full_html.replace("./", "../").replace("<a href=\"", "<a href=\"../")
            }

            if let Some(parent) = output_file.parent() {
                // 創(chuàng)建所有必要的父文件夾
                fs::create_dir_all(parent).expect("create html parent dir failed");
            }
            fs::write(output_file, full_html).expect("Failed to write HTML file");
        }
    }

    // ... 復(fù)制靜態(tài)資源 ...
    // 定義靜態(tài)資源目錄和目標目錄
    let static_dir = Path::new(static_dir);
    let output_dir = Path::new(output_dir);

    // 復(fù)制靜態(tài)資源
    if static_dir.exists() {
        copy_dir_all(static_dir, output_dir).expect("Failed to copy static files");
    }

    println!("Site built successfully.");
}

生成html文件這里需要注意幾個點:

  • 第一個是文件路徑,需要把html生成到配置的輸出目錄,需要一個path轉(zhuǎn)換邏輯;
  • summary里面的鏈接需要處理,默認是.md,需要轉(zhuǎn)為.html
  • 所有鏈接的相對路徑需要處理,根據(jù)目錄都是用相對路徑;
  • 復(fù)制靜態(tài)資源時,也需要注意文件路徑,以及文件夾是否存在。

第五步,實現(xiàn)run命令

這里由于只是本地運行查看html,所以選擇tiny_http,啟動一個簡單的http服務(wù)。核心代碼如下:

pub fn run_command() {
    // 讀取配置文件
    let config = fs::read_to_string("md_config.toml").expect("Unable to read config file");
    let parsed_config = config.parse::<Value>().expect("Unable to parse config");
    let port = parsed_config.get("port").and_then(Value::as_str).unwrap_or("9900");
    let output_dir = parsed_config.get("output_dir").and_then(Value::as_str).unwrap_or(".site");
    let address = format!("0.0.0.0:{}", port);
    let server = Server::http(address).unwrap();
    println!("Running local server on port {}", port);

    for request in server.incoming_requests() {
        let url = if request.url() == "/" {
            "/index.html" // 使用 index.html 作為根路徑的默認頁面
        } else {
            request.url()
        };

        let file_path = PathBuf::from(output_dir).join(&url[1..]); // 移除 URL 的首個斜杠
        match fs::read(&file_path) {
            Ok(contents) => {
                let response = Response::from_data(contents).with_header(
                    Header::from_bytes("Content-Type", "text/html; charset=utf-8").unwrap(),
                );
                request.respond(response).unwrap();
            }
            Err(_) => {
                let response = Response::from_string("Not Found").with_status_code(404);
                request.respond(response).unwrap();
            }
        }
    }
}

這里需要注意的是,直接返回html會中文亂碼,所以統(tǒng)一都加了Content-Type", "text/html; charset=utf-8

第六步,展示成果

新建一個用于測試的博客目錄:

  • 在博客工具目錄執(zhí)行cargo run生成執(zhí)行的命令文件;
  • 復(fù)制博客工具命令,cp target/debug/rust_md_site_tool ~/.cargo/bin;
  • 執(zhí)行 rust_md_site_tool init初始化博客;
  • 在docs目錄新建summary.mdindex.md,并在summary里創(chuàng)建好測試的md文檔和鏈接;
  • rust_md_site_tool build構(gòu)建目錄;
  • 打開瀏覽器 http://localhost:9900/ ;可以訪問index.html;

到此這篇關(guān)于利用rust編一個靜態(tài)博客工具的文章就介紹到這了,更多相關(guān)rust靜態(tài)博客內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Rust突破編譯器限制構(gòu)造可修改的全局變量

    Rust突破編譯器限制構(gòu)造可修改的全局變量

    這篇文章主要為大家介紹了Rust突破編譯器限制構(gòu)造可修改的全局變量示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10
  • Rust中的宏之聲明宏和過程宏詳解

    Rust中的宏之聲明宏和過程宏詳解

    Rust中的宏是一種強大的工具,可以幫助開發(fā)人員編寫可重用、高效和靈活的代碼,這篇文章主要介紹了Rust中的宏:聲明宏和過程宏,需要的朋友可以參考下
    2023-04-04
  • rust異步編程詳細講解

    rust異步編程詳細講解

    這篇文章主要介紹了rust異步編程,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-12-12
  • Rust中字符串類型String的46種常用方法分享

    Rust中字符串類型String的46種常用方法分享

    Rust主要有兩種類型的字符串:&str和String,本文主要為大家介紹的是String類型的字符串以及它常用的46種方法,感興趣的小伙伴可以了解一下
    2023-06-06
  • Rust中引用和指針的區(qū)別詳解

    Rust中引用和指針的區(qū)別詳解

    在 Rust 中,指針和引用都可以用來指向內(nèi)存中的某個值,它們之間的主要區(qū)別在于它們的安全性和生命周期保證,本文將通過一個簡單的示例給大家介紹一下Rust中引用和指針的區(qū)別,需要的朋友可以參考下
    2023-08-08
  • 深入了解Rust中函數(shù)與閉包的使用

    深入了解Rust中函數(shù)與閉包的使用

    本文主要介紹一下Rust函數(shù)相關(guān)的內(nèi)容,首先函數(shù)我們其實一直都在用,所以函數(shù)本身沒什么可說的,我們的重點是與函數(shù)相關(guān)的閉包、高階函數(shù)、發(fā)散函數(shù),感興趣的可以學(xué)習(xí)一下
    2022-11-11
  • Rust?Postgres實例代碼

    Rust?Postgres實例代碼

    Rust Postgres是一個純Rust實現(xiàn)的PostgreSQL客戶端庫,本文主要介紹了Rust?Postgres實例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-05-05
  • rust標準庫std::env環(huán)境相關(guān)的常量

    rust標準庫std::env環(huán)境相關(guān)的常量

    在本章節(jié)中, 我們探討了Rust處理命令行參數(shù)的常見的兩種方式和處理環(huán)境變量的兩種常見方式, 拋開Rust的語法, 實際上在命令行參數(shù)的處理方式上, 與其它語言大同小異, 可能影響我們習(xí)慣的也就只剩下語法,本文介紹rust標準庫std::env的相關(guān)知識,感興趣的朋友一起看看吧
    2024-03-03
  • Rust使用libloader調(diào)用動態(tài)鏈接庫

    Rust使用libloader調(diào)用動態(tài)鏈接庫

    這篇文章主要為大家介紹了Rust使用libloader調(diào)用動態(tài)鏈接庫示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • 一步到位,教你如何在Windows成功安裝Rust

    一步到位,教你如何在Windows成功安裝Rust

    一步到位:輕松學(xué)會在Windows上安裝Rust!想快速掌握Rust編程語言?別再為復(fù)雜教程頭疼!這份指南將手把手帶你順利完成Windows平臺上的Rust安裝全過程,從此編碼之旅更加順暢無阻,立即閱讀,開始你的Rust編程旅程吧!
    2024-01-01

最新評論