wikipedia working, and many other improvements
This commit is contained in:
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -604,9 +604,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ming-wm-lib"
|
name = "ming-wm-lib"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1c99c21afb59198e739b84a847f8d677fbdd87c4afd2a45d6cbba5dc070e1802"
|
checksum = "79963d3f8d79e0bd7b4530b52448fbcb3be82dbf6901ffa99e870b1a28f8820e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ name = "mingInternet_Koxinga_Browser"
|
|||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ming-wm-lib = "0.1.2"
|
ming-wm-lib = "0.1.3"
|
||||||
reqwest = { version = "0.12", features = [ "blocking" ] }
|
reqwest = { version = "0.12", features = [ "blocking" ] }
|
||||||
|
|||||||
12
README.md
12
README.md
@@ -1 +1,13 @@
|
|||||||
A web browser for [ming-wm](https://github.com/stjet/ming-wm), and developed in it, that aims to support two things: text, and links.
|
A web browser for [ming-wm](https://github.com/stjet/ming-wm), and developed in it, that aims to support two things: text, and links.
|
||||||
|
|
||||||
|
Yes, slightly inspired by [Vimium](https://vimium.github.io).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Hacker News frontpage:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Wikipedia article:
|
||||||
|
|
||||||
|

|
||||||
|
|||||||
2
install
Normal file
2
install
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
cp ./target/release/mingInternet_Koxinga_Browser /usr/local/bin/mingInternet_Koxinga_Browser
|
||||||
BIN
koxinga_hn.png
Normal file
BIN
koxinga_hn.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 153 KiB |
BIN
koxinga_wiki.png
Normal file
BIN
koxinga_wiki.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 294 KiB |
BIN
koxinga_within.png
Normal file
BIN
koxinga_within.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 196 KiB |
@@ -1,2 +1,2 @@
|
|||||||
#!/bin/bash
|
#!/bin/sh
|
||||||
cp ./target/release/mingInternet_Koxinga_Browser ~/.local/bin/mingInternet_Koxinga_Browser
|
cp ./target/release/mingInternet_Koxinga_Browser ~/.local/bin/mingInternet_Koxinga_Browser
|
||||||
221
src/main.rs
221
src/main.rs
@@ -17,11 +17,27 @@ use crate::xml::{ parse, Node, OutputType };
|
|||||||
|
|
||||||
const LINE_HEIGHT: usize = 18;
|
const LINE_HEIGHT: usize = 18;
|
||||||
|
|
||||||
|
fn get_base_url(url: &str) -> String {
|
||||||
|
let mut base_url = String::new();
|
||||||
|
let mut slash = 0;
|
||||||
|
for c in url.chars() {
|
||||||
|
if c == '/' {
|
||||||
|
slash += 1;
|
||||||
|
if slash == 3 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
base_url += &c.to_string();
|
||||||
|
}
|
||||||
|
base_url
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, PartialEq)]
|
#[derive(Default, PartialEq)]
|
||||||
enum Mode {
|
enum Mode {
|
||||||
#[default]
|
#[default]
|
||||||
Normal,
|
Normal,
|
||||||
Url,
|
Url,
|
||||||
|
Link,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Mode {
|
impl fmt::Display for Mode {
|
||||||
@@ -29,6 +45,7 @@ impl fmt::Display for Mode {
|
|||||||
fmt.write_str(match self {
|
fmt.write_str(match self {
|
||||||
Mode::Normal => "NORMAL",
|
Mode::Normal => "NORMAL",
|
||||||
Mode::Url => "URL",
|
Mode::Url => "URL",
|
||||||
|
Mode::Link => "LINK",
|
||||||
})?;
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -38,9 +55,14 @@ impl fmt::Display for Mode {
|
|||||||
struct KoxingaBrowser {
|
struct KoxingaBrowser {
|
||||||
dimensions: Dimensions,
|
dimensions: Dimensions,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
|
max_lines: usize,
|
||||||
top_line_no: usize,
|
top_line_no: usize,
|
||||||
|
url: Option<String>,
|
||||||
url_input: String,
|
url_input: String,
|
||||||
|
link_input: String,
|
||||||
|
links: Vec<String>,
|
||||||
top_level_nodes: Vec<Box<Node>>,
|
top_level_nodes: Vec<Box<Node>>,
|
||||||
|
page: Vec<(usize, usize, String, bool)>, //x, y, text, link colour or not
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowLike for KoxingaBrowser {
|
impl WindowLike for KoxingaBrowser {
|
||||||
@@ -52,21 +74,37 @@ impl WindowLike for KoxingaBrowser {
|
|||||||
},
|
},
|
||||||
WindowMessage::ChangeDimensions(dimensions) => {
|
WindowMessage::ChangeDimensions(dimensions) => {
|
||||||
self.dimensions = dimensions;
|
self.dimensions = dimensions;
|
||||||
|
self.calc_page();
|
||||||
WindowMessageResponse::JustRedraw
|
WindowMessageResponse::JustRedraw
|
||||||
},
|
},
|
||||||
WindowMessage::KeyPress(key_press) => {
|
WindowMessage::KeyPress(key_press) => {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
Mode::Normal => {
|
Mode::Normal => {
|
||||||
|
let max_lines_screen = (self.dimensions[1] - 4) / LINE_HEIGHT - 1;
|
||||||
if key_press.key == 'u' {
|
if key_press.key == 'u' {
|
||||||
self.mode = Mode::Url;
|
self.mode = Mode::Url;
|
||||||
WindowMessageResponse::JustRedraw
|
WindowMessageResponse::JustRedraw
|
||||||
|
} else if key_press.key == 'l' && self.url.is_some() {
|
||||||
|
self.mode = Mode::Link;
|
||||||
|
self.calc_page();
|
||||||
|
WindowMessageResponse::JustRedraw
|
||||||
} else if key_press.key == 'k' {
|
} else if key_press.key == 'k' {
|
||||||
if self.top_line_no > 0 {
|
if self.top_line_no > 0 {
|
||||||
self.top_line_no -= 1;
|
self.top_line_no -= 1;
|
||||||
}
|
}
|
||||||
WindowMessageResponse::JustRedraw
|
WindowMessageResponse::JustRedraw
|
||||||
} else if key_press.key == 'j' {
|
} else if key_press.key == 'j' {
|
||||||
self.top_line_no += 1;
|
if self.top_line_no < self.max_lines - max_lines_screen {
|
||||||
|
self.top_line_no += 1;
|
||||||
|
WindowMessageResponse::JustRedraw
|
||||||
|
} else {
|
||||||
|
WindowMessageResponse::DoNothing
|
||||||
|
}
|
||||||
|
} else if key_press.key == '0' {
|
||||||
|
self.top_line_no = 0;
|
||||||
|
WindowMessageResponse::JustRedraw
|
||||||
|
} else if key_press.key == 'G' {
|
||||||
|
self.top_line_no = self.max_lines - max_lines_screen;
|
||||||
WindowMessageResponse::JustRedraw
|
WindowMessageResponse::JustRedraw
|
||||||
} else {
|
} else {
|
||||||
WindowMessageResponse::DoNothing
|
WindowMessageResponse::DoNothing
|
||||||
@@ -75,8 +113,10 @@ impl WindowLike for KoxingaBrowser {
|
|||||||
Mode::Url => {
|
Mode::Url => {
|
||||||
if key_press.key == '𐘂' { //the enter key
|
if key_press.key == '𐘂' { //the enter key
|
||||||
if let Some(text) = get(&self.url_input) {
|
if let Some(text) = get(&self.url_input) {
|
||||||
|
self.url = Some(self.url_input.clone());
|
||||||
self.top_line_no = 0;
|
self.top_line_no = 0;
|
||||||
self.top_level_nodes = parse(&text);
|
self.top_level_nodes = parse(&text);
|
||||||
|
self.calc_page();
|
||||||
self.mode = Mode::Normal;
|
self.mode = Mode::Normal;
|
||||||
}
|
}
|
||||||
} else if key_press.key == '𐘃' { //escape key
|
} else if key_press.key == '𐘃' { //escape key
|
||||||
@@ -92,6 +132,48 @@ impl WindowLike for KoxingaBrowser {
|
|||||||
}
|
}
|
||||||
WindowMessageResponse::JustRedraw
|
WindowMessageResponse::JustRedraw
|
||||||
},
|
},
|
||||||
|
Mode::Link => {
|
||||||
|
if key_press.key == '𐘂' && self.link_input.len() > 0 { //the enter key
|
||||||
|
let link_index = self.link_input.parse::<usize>().unwrap();
|
||||||
|
let url = self.url.as_ref().unwrap();
|
||||||
|
if link_index < self.links.len() {
|
||||||
|
let mut link = self.links[link_index].clone();
|
||||||
|
if link.chars().count() >= 2 {
|
||||||
|
//remove the quotes
|
||||||
|
link = link.substring(1, link.len() - 1).to_string();
|
||||||
|
}
|
||||||
|
if link.starts_with("/") {
|
||||||
|
link = get_base_url(&url) + &link;
|
||||||
|
} else if !link.starts_with("http://") && !link.starts_with("https://") {
|
||||||
|
link = url.clone() + if url.ends_with("/") { "" } else { "/" } + &link;
|
||||||
|
}
|
||||||
|
if let Some(text) = get(&link) {
|
||||||
|
self.url = Some(link.to_string());
|
||||||
|
self.url_input = link.to_string();
|
||||||
|
self.top_line_no = 0;
|
||||||
|
self.top_level_nodes = parse(&text);
|
||||||
|
self.mode = Mode::Normal;
|
||||||
|
self.calc_page();
|
||||||
|
}
|
||||||
|
self.link_input = String::new();
|
||||||
|
}
|
||||||
|
self.mode = Mode::Normal;
|
||||||
|
WindowMessageResponse::JustRedraw
|
||||||
|
} else if key_press.key == '𐘃' { //escape key'
|
||||||
|
self.link_input = String::new();
|
||||||
|
self.mode = Mode::Normal;
|
||||||
|
self.calc_page();
|
||||||
|
WindowMessageResponse::JustRedraw
|
||||||
|
} else if key_press.key == '𐘁' { //backspace
|
||||||
|
self.link_input = self.link_input.remove_last();
|
||||||
|
WindowMessageResponse::JustRedraw
|
||||||
|
} else if key_press.key.is_ascii_digit() && self.link_input.len() < 10 {
|
||||||
|
self.link_input += &key_press.key.to_string();
|
||||||
|
WindowMessageResponse::JustRedraw
|
||||||
|
} else {
|
||||||
|
WindowMessageResponse::DoNothing
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => WindowMessageResponse::DoNothing,
|
_ => WindowMessageResponse::DoNothing,
|
||||||
@@ -100,64 +182,19 @@ impl WindowLike for KoxingaBrowser {
|
|||||||
|
|
||||||
fn draw(&self, theme_info: &ThemeInfo) -> Vec<DrawInstructions> {
|
fn draw(&self, theme_info: &ThemeInfo) -> Vec<DrawInstructions> {
|
||||||
let mut instructions = Vec::new();
|
let mut instructions = Vec::new();
|
||||||
let mut outputs = Vec::new();
|
let max_lines_screen = (self.dimensions[1] - 4) / LINE_HEIGHT - 1;
|
||||||
if self.top_level_nodes.len() > 0 {
|
for p in &self.page {
|
||||||
let html_index = self.top_level_nodes.iter().position(|n| n.tag_name == "html");
|
let line_no = (p.1 - 2) / LINE_HEIGHT;
|
||||||
if let Some(html_index) = html_index {
|
if line_no >= self.top_line_no && line_no < self.top_line_no + max_lines_screen {
|
||||||
for n in &self.top_level_nodes[html_index].children {
|
instructions.push(DrawInstructions::Text([p.0, p.1 - LINE_HEIGHT * self.top_line_no], vec!["nimbus-roman".to_string()], p.2.clone(), if p.3 { theme_info.top_text } else { theme_info.text }, theme_info.background, Some(1), Some(12)));
|
||||||
if n.tag_name == "body" {
|
|
||||||
outputs = n.to_output();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut y = 2;
|
|
||||||
let mut x = 2;
|
|
||||||
let mut colour = theme_info.text;
|
|
||||||
for o in outputs {
|
|
||||||
//each char is width of 13
|
|
||||||
match o {
|
|
||||||
OutputType::Text(s) => {
|
|
||||||
//leading and trailing whitespace is probably a mistake
|
|
||||||
let s = s.trim();
|
|
||||||
let mut line = String::new();
|
|
||||||
let mut start_x = x;
|
|
||||||
for c in s.chars() {
|
|
||||||
if x + 14 > self.dimensions[0] {
|
|
||||||
//full line, add draw instruction
|
|
||||||
let line_no = (y - 2) / LINE_HEIGHT;
|
|
||||||
if line_no >= self.top_line_no {
|
|
||||||
instructions.push(DrawInstructions::Text([start_x, y - LINE_HEIGHT * self.top_line_no], vec!["nimbus-roman".to_string()], line, colour, theme_info.background, Some(1), Some(14)));
|
|
||||||
}
|
|
||||||
line = String::new();
|
|
||||||
x = 2;
|
|
||||||
start_x = x;
|
|
||||||
y += LINE_HEIGHT;
|
|
||||||
}
|
|
||||||
line += &c.to_string();
|
|
||||||
x += 14;
|
|
||||||
}
|
|
||||||
let line_no = (y - 2) / LINE_HEIGHT;
|
|
||||||
if line.len() > 0 && line_no >= self.top_line_no {
|
|
||||||
instructions.push(DrawInstructions::Text([start_x, y - LINE_HEIGHT * self.top_line_no], vec!["nimbus-roman".to_string()], line, colour, theme_info.background, Some(1), Some(14)));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
OutputType::Newline => {
|
|
||||||
x = 2;
|
|
||||||
y += LINE_HEIGHT;
|
|
||||||
},
|
|
||||||
OutputType::StartLink(_) => {
|
|
||||||
colour = theme_info.top_text;
|
|
||||||
},
|
|
||||||
OutputType::EndLink => {
|
|
||||||
colour = theme_info.text;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
//mode
|
//mode
|
||||||
let mut bottom_text = self.mode.to_string() + ": ";
|
let mut bottom_text = self.mode.to_string() + ": ";
|
||||||
if self.mode == Mode::Url {
|
if self.mode == Mode::Url {
|
||||||
bottom_text += &self.url_input;
|
bottom_text += &self.url_input;
|
||||||
|
} else if self.mode == Mode::Link {
|
||||||
|
bottom_text += &self.link_input;
|
||||||
}
|
}
|
||||||
instructions.push(DrawInstructions::Text([0, self.dimensions[1] - LINE_HEIGHT], vec!["nimbus-roman".to_string()], bottom_text, theme_info.text, theme_info.background, Some(1), Some(12)));
|
instructions.push(DrawInstructions::Text([0, self.dimensions[1] - LINE_HEIGHT], vec!["nimbus-roman".to_string()], bottom_text, theme_info.text, theme_info.background, Some(1), Some(12)));
|
||||||
instructions
|
instructions
|
||||||
@@ -184,6 +221,84 @@ impl KoxingaBrowser {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn calc_page(&mut self) {
|
||||||
|
self.page = Vec::new();
|
||||||
|
self.links = Vec::new();
|
||||||
|
let mut outputs = Vec::new();
|
||||||
|
if self.top_level_nodes.len() > 0 {
|
||||||
|
let html_index = self.top_level_nodes.iter().position(|n| n.tag_name == "html");
|
||||||
|
if let Some(html_index) = html_index {
|
||||||
|
for n in &self.top_level_nodes[html_index].children {
|
||||||
|
if n.tag_name == "body" {
|
||||||
|
outputs = n.to_output();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut y = 2;
|
||||||
|
let mut x = 2;
|
||||||
|
let mut colour = false;
|
||||||
|
let mut link_counter = 0;
|
||||||
|
for o in outputs {
|
||||||
|
//each char is width of 13
|
||||||
|
let os = if let OutputType::Text(ref s) = o {
|
||||||
|
let s = if s.starts_with(" ") {
|
||||||
|
" ".to_string()
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
} + s.trim() + if s.ends_with(" ") {
|
||||||
|
" "
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
Some(s)
|
||||||
|
} else if let OutputType::StartLink(link) = &o {
|
||||||
|
colour = true;
|
||||||
|
if self.mode == Mode::Link {
|
||||||
|
self.links.push(link.to_string());
|
||||||
|
let s = link_counter.to_string() + ":";
|
||||||
|
link_counter += 1;
|
||||||
|
if self.mode == Mode::Link {
|
||||||
|
Some(s)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
if let Some(s) = os {
|
||||||
|
//leading and trailing whitespace is probably a mistake
|
||||||
|
let mut line = String::new();
|
||||||
|
let mut start_x = x;
|
||||||
|
for c in s.chars() {
|
||||||
|
if x + 14 > self.dimensions[0] {
|
||||||
|
//full line, add draw instruction
|
||||||
|
self.page.push((start_x, y, line, colour));
|
||||||
|
line = String::new();
|
||||||
|
x = 2;
|
||||||
|
start_x = x;
|
||||||
|
y += LINE_HEIGHT;
|
||||||
|
}
|
||||||
|
line += &c.to_string();
|
||||||
|
x += 13;
|
||||||
|
}
|
||||||
|
if line.len() > 0 {
|
||||||
|
self.page.push((start_x, y, line, colour));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if o == OutputType::Newline {
|
||||||
|
x = 2;
|
||||||
|
y += LINE_HEIGHT;
|
||||||
|
} else if o == OutputType::EndLink {
|
||||||
|
colour = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.max_lines = (y - 2) / LINE_HEIGHT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
|
|||||||
78
src/xml.rs
78
src/xml.rs
@@ -2,16 +2,23 @@ use std::vec::Vec;
|
|||||||
use std::boxed::Box;
|
use std::boxed::Box;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use ming_wm_lib::utils::Substring;
|
||||||
|
|
||||||
//try to be xhtml compliant?
|
//try to be xhtml compliant?
|
||||||
|
|
||||||
//fuck these mfers. self close with a FUCKING slash man.
|
//fuck these mfers. self close with a FUCKING slash man.
|
||||||
//<meta> is bad, <meta/> is good!!
|
//<meta> is bad, <meta/> is good!!
|
||||||
const SELF_CLOSING: [&'static str; 7] = ["link", "meta", "input", "img", "br", "hr", "!DOCTYPE"];
|
const SELF_CLOSING: [&'static str; 9] = ["link", "meta", "input", "img", "br", "hr", "source", "track", "!DOCTYPE"];
|
||||||
|
|
||||||
fn is_whitespace(c: char) -> bool {
|
fn is_whitespace(c: char) -> bool {
|
||||||
c == ' ' || c == '\x09'
|
c == ' ' || c == '\x09'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_escaped(s: &str) -> String {
|
||||||
|
s.replace(" ", " ").replace("'", "'").to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
pub enum OutputType {
|
pub enum OutputType {
|
||||||
StartLink(String),
|
StartLink(String),
|
||||||
EndLink,
|
EndLink,
|
||||||
@@ -33,7 +40,7 @@ impl Node {
|
|||||||
let mut output = Vec::new();
|
let mut output = Vec::new();
|
||||||
let mut link = false;
|
let mut link = false;
|
||||||
if self.text_node {
|
if self.text_node {
|
||||||
output.push(OutputType::Text(self.tag_name.clone()));
|
output.push(OutputType::Text(handle_escaped(&self.tag_name.clone())));
|
||||||
return output;
|
return output;
|
||||||
} else if self.tag_name == "script" || self.tag_name == "style" {
|
} else if self.tag_name == "script" || self.tag_name == "style" {
|
||||||
//ignore script and style tags
|
//ignore script and style tags
|
||||||
@@ -86,7 +93,54 @@ pub fn parse(xml_string: &str) -> Vec<Box<Node>> {
|
|||||||
}
|
}
|
||||||
let c = c.unwrap();
|
let c = c.unwrap();
|
||||||
if let Some(ref mut n) = current_node {
|
if let Some(ref mut n) = current_node {
|
||||||
if c == ' ' && recording_tag_name && !n.text_node {
|
if n.tag_name == "!--" {
|
||||||
|
//this is a comment... skip!
|
||||||
|
current_node = None;
|
||||||
|
recording_tag_name = false;
|
||||||
|
let mut dash_count = 0;
|
||||||
|
loop {
|
||||||
|
let c2 = chars.next();
|
||||||
|
if c2.is_none() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let c2 = c2.unwrap();
|
||||||
|
if c2 == '>' && dash_count == 2 {
|
||||||
|
break;
|
||||||
|
} else if c2 == '-' {
|
||||||
|
dash_count += 1;
|
||||||
|
} else {
|
||||||
|
dash_count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (n.tag_name == "script" || n.tag_name == "style") && !n.text_node {
|
||||||
|
//need to handle this carefully since < and > could be present
|
||||||
|
let mut so_far = String::new();
|
||||||
|
let loc = add_to_parent(&mut top_level_nodes, &parent_location, n.clone());
|
||||||
|
parent_location.push(loc);
|
||||||
|
//won't handle if </script> appears in a string
|
||||||
|
loop {
|
||||||
|
let c2 = chars.next();
|
||||||
|
if c2.is_none() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let c2 = c2.unwrap();
|
||||||
|
so_far += &c2.to_string();
|
||||||
|
let end_len = n.tag_name.len() + 3;
|
||||||
|
if so_far.len() >= end_len {
|
||||||
|
let end = so_far.chars().count();
|
||||||
|
if so_far.substring(end - end_len, end) == "</".to_string() + &n.tag_name + ">" {
|
||||||
|
current_node = None;
|
||||||
|
let mut n2: Node = Default::default();
|
||||||
|
n2.text_node = true;
|
||||||
|
n2.tag_name = so_far.substring(0, end - end_len).to_string();
|
||||||
|
add_to_parent(&mut top_level_nodes, &parent_location, n2);
|
||||||
|
parent_location.pop();
|
||||||
|
recording_tag_name = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if c == ' ' && recording_tag_name && !n.text_node {
|
||||||
recording_tag_name = false;
|
recording_tag_name = false;
|
||||||
} else if c == '>' || (c == '/' && chars.peek().unwrap_or(&' ') == &'>') || (n.text_node && chars.peek().unwrap_or(&' ') == &'<') {
|
} else if c == '>' || (c == '/' && chars.peek().unwrap_or(&' ') == &'>') || (n.text_node && chars.peek().unwrap_or(&' ') == &'<') {
|
||||||
if n.text_node {
|
if n.text_node {
|
||||||
@@ -202,4 +256,22 @@ fn test_close_xml_parse() {
|
|||||||
assert!(nodes[2].tag_name == "span");
|
assert!(nodes[2].tag_name == "span");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_style_script_xml_parse() {
|
||||||
|
let nodes = parse("<p>a b c</p><style>. p ></style><b>woah</b>");
|
||||||
|
assert!(nodes.len() == 3);
|
||||||
|
assert!(nodes[0].tag_name == "p");
|
||||||
|
assert!(nodes[1].tag_name == "style");
|
||||||
|
assert!(nodes[1].children[0].tag_name == ". p >");
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_comments_xml_parse() {
|
||||||
|
let nodes = parse("<p>test</p><!--comment <a>stallman forced me to do this</a><p>--><b> afterwards</b>");
|
||||||
|
assert!(nodes.len() == 2);
|
||||||
|
assert!(nodes[1].tag_name == "b");
|
||||||
|
assert!(nodes[1].children[0].tag_name == " afterwards");
|
||||||
|
}
|
||||||
|
|
||||||
//more tests 100% needed. yoink from news.ycombinator.com and en.wikipedia.org
|
//more tests 100% needed. yoink from news.ycombinator.com and en.wikipedia.org
|
||||||
|
|||||||
Reference in New Issue
Block a user