Skip to content

Commit

Permalink
Merge branch 'one-pass' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
WGUNDERWOOD committed Aug 31, 2024
2 parents 2a3554f + 8191024 commit 9589405
Show file tree
Hide file tree
Showing 27 changed files with 9,094 additions and 8,550 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ tex-fmt is hundreds of times faster than latexindent.

| **Files** | **Lines** | **Size** | **tex-fmt** | **latexindent** | **latexindent -m** |
| --- | --- | --- | --- | --- | --- |
| 47 | 93k | 3.5M | **0.143s** | 102.1s [x714] | 128.4s [x898] |
| 47 | 93k | 3.5M | **0.096s** | 97s [x1001] | 125s [x1288] |

## Limitations

Expand Down
24 changes: 7 additions & 17 deletions extra/prof.sh
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
#!/usr/bin/env bash
echo "Making flamegraph profile"
DIR="$(mktemp -d)"
cp "../tests/source/phd_dissertation.tex" "$DIR"
cp -r ../tests/* "$DIR"
cargo build --release

echo "Writing large test file"
for _ in {1..5}; do
cat "$DIR/phd_dissertation.tex" >> "$DIR/large.tex"
printf "\n\n\n" >> "$DIR/large.tex"
done
echo
echo -n "Test files: $(find "$DIR"/*/* | wc -l) files, "
echo -n "$(wc -l --total=only "$DIR"/source/* "$DIR"/target/*) lines, "
du -hs "$DIR" | cut -f 1
echo

rm "$DIR/phd_dissertation.tex"

echo "Test file:"
for f in "$DIR"/*.tex; do
echo -n " $(basename "$f"), "
echo -n "$(wc -l "$f" | cut --delimiter=" " --fields 1) lines, "
du -h "$f" | cut --fields 1
done

flamegraph -F 10000 -- ../target/release/tex-fmt "$DIR"/*.tex
hyperfine --warmup 2 -n "tex-fmt" "../target/release/tex-fmt $DIR/*.tex"
flamegraph -F 10000 -- ../target/release/tex-fmt "$DIR/source/"* "$DIR/target/"*
3 changes: 3 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ build:
test:
@cargo test -r

testignored:
@cargo test -r -- --ignored

clippy:
@cargo clippy -r

Expand Down
27 changes: 0 additions & 27 deletions notes.org
Original file line number Diff line number Diff line change
@@ -1,28 +1 @@
#+title: tex-fmt
* Tasks
** Check other latex files
** Tidy code
** Documentation
** Try wrapping spaceless lines
* Features
** Aim for a single pass of wrapping and indenting
*** Three lists of strings
**** 1: lines of original file
**** 2: lines in processing queue
**** 3: lines of formatted file
*** Logic flow
**** If the queue is empty
***** Take a line from the original file and put it in the queue
**** Else
***** Indent the first line in the queue with the global indentation state
***** Keep the new indentation state in a temporary variable
***** If it then needs wrapping
****** Wrap it into several lines and push them all back onto the queue
***** Else
****** Move it from the queue to the output file
****** Update the global indentation state from the temporary variable
** Parsing with texlab
*** https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/syntax.md
*** https://github.com/latex-lsp/texlab/tree/master/crates/parser
** Parsing with pest
** Parsing with nom
1 change: 1 addition & 0 deletions shell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pkgs.mkShell {
pillow
]);
in [
pkgs.bacon
pkgs.cacert
pkgs.cargo-flamegraph
pkgs.cargo-edit
Expand Down
125 changes: 67 additions & 58 deletions src/format.rs
Original file line number Diff line number Diff line change
@@ -1,80 +1,89 @@
use crate::ignore::*;
use crate::indent::*;
use crate::leave::*;
use crate::logging::*;
use crate::parse::*;
use crate::subs::*;
use crate::wrap::*;
use crate::Cli;
use log::Level::{Info, Warn};

const MAX_PASS: usize = 10;

fn apply_passes(
pub fn format_file(
text: &str,
file: &str,
args: &Cli,
logs: &mut Vec<Log>,
) -> String {
let mut new_text = apply_indent(text, file, args, logs, Some(1));
let mut finished = false;
let mut pass = 2;
record_file_log(logs, Info, file, "Formatting started.");
let mut old_text = remove_extra_newlines(text);
old_text = environments_new_line(&old_text, file, args, logs);
old_text = remove_tabs(&old_text);
old_text = remove_trailing_spaces(&old_text);

let mut state = State::new();

let mut old_lines = old_text.lines().enumerate();

let mut queue: Vec<(usize, String)> = vec![];
let mut new_text = String::with_capacity(text.len());

while !finished && needs_wrap(&new_text) && pass < MAX_PASS + 2 {
let old_text = new_text.clone();
new_text = wrap(&new_text, file, logs, Some(pass), args);
new_text = remove_trailing_spaces(&new_text);
new_text = apply_indent(&new_text, file, args, logs, Some(pass));
pass += 1;
if new_text == old_text {
finished = true;
loop {
if let Some((linum_old, mut line)) = queue.pop() {
let temp_state: State;
(line, temp_state) =
apply_indent(&line, linum_old, &state, logs, file, args);
if needs_wrap(&line, &temp_state, args) {
let wrapped_lines =
apply_wrap(&line, &temp_state, file, args, logs);
if wrapped_lines.is_some() {
queue.push((linum_old, wrapped_lines.clone().unwrap().1));
queue.push((linum_old, wrapped_lines.clone().unwrap().0));
} else {
new_text.push_str(&line);
new_text.push('\n');
state.linum_new += 1;
};
} else {
state = temp_state;
new_text.push_str(&line);
new_text.push('\n');
}
} else if let Some((linum_old, line)) = old_lines.next() {
queue.push((linum_old, line.to_string()));
} else {
break;
}
}

record_log(
logs,
Info,
None,
file.to_string(),
None,
None,
"Passes completed.".to_string(),
);

// check indents return to zero
if new_text.lines().last().unwrap_or_default().starts_with(' ') {
record_log(
logs,
Warn,
None,
file.to_string(),
None,
None,
"Indent does not return to zero.".to_string(),
);
if !indents_return_to_zero(&new_text) {
record_file_log(logs, Warn, file, "Indent does not return to zero.");
}

record_file_log(logs, Info, file, "Formatting complete.");

new_text
}

pub fn format_file(
text: &str,
file: &str,
args: &Cli,
logs: &mut Vec<Log>,
) -> String {
if args.verbose {
record_log(
logs,
Info,
None,
file.to_string(),
None,
None,
"Begin formatting.".to_string(),
);
#[derive(Clone, Debug)]
pub struct State {
pub linum_old: usize,
pub linum_new: usize,
pub ignore: Ignore,
pub indent: Indent,
pub leave: Leave,
}

impl State {
pub fn new() -> Self {
State {
linum_old: 0,
linum_new: 0,
ignore: Ignore::new(),
indent: Indent::new(),
leave: Leave::new(),
}
}
let mut new_text = remove_extra_newlines(text);
new_text = environments_new_line(&new_text, file, args, logs);
new_text = remove_tabs(&new_text);
new_text = remove_trailing_spaces(&new_text);
new_text = apply_passes(&new_text, file, args, logs);
new_text
}

fn indents_return_to_zero(text: &str) -> bool {
!text.lines().last().unwrap_or_default().starts_with(' ')
}
42 changes: 21 additions & 21 deletions src/ignore.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::format::*;
use crate::logging::*;
use log::Level::Warn;

#[derive(Clone, Debug)]
pub struct Ignore {
pub actual: bool,
pub visual: bool,
Expand All @@ -17,11 +19,9 @@ impl Ignore {

pub fn get_ignore(
line: &str,
linum: usize,
ignore: Ignore,
file: &str,
state: &State,
logs: &mut Vec<Log>,
pass: Option<usize>,
file: &str,
warn: bool,
) -> Ignore {
let skip = contains_ignore_skip(line);
Expand All @@ -31,39 +31,39 @@ pub fn get_ignore(
let visual: bool;

if skip {
actual = ignore.actual;
actual = state.ignore.actual;
visual = true;
} else if begin {
actual = true;
visual = true;
if warn && ignore.actual {
record_log(
if warn && state.ignore.actual {
record_line_log(
logs,
Warn,
pass,
file.to_string(),
Some(linum),
Some(line.to_string()),
"Cannot begin ignore block:".to_string(),
file,
state.linum_new,
state.linum_old,
line,
"Cannot begin ignore block:",
);
}
} else if end {
actual = false;
visual = true;
if warn && !ignore.actual {
record_log(
if warn && !state.ignore.actual {
record_line_log(
logs,
Warn,
pass,
file.to_string(),
Some(linum),
Some(line.to_string()),
"No ignore block to end:".to_string(),
file,
state.linum_new,
state.linum_old,
line,
"No ignore block to end.",
);
}
} else {
actual = ignore.actual;
visual = ignore.actual;
actual = state.ignore.actual;
visual = state.ignore.actual;
}

Ignore { actual, visual }
Expand Down
Loading

0 comments on commit 9589405

Please sign in to comment.