CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Tools/langtool/src/inifile.rs
Views: 1401
use std::fs::File;1use std::io::{self, Write};2use std::path::{Path, PathBuf};34use crate::section::Section;56#[derive(Debug)]7pub struct IniFile {8pub filename: PathBuf,9pub preamble: Vec<String>,10pub sections: Vec<Section>,11pub has_bom: bool,12}1314impl IniFile {15pub fn parse(filename: &str) -> io::Result<IniFile> {16let lines = read_lines(filename)?;1718let mut sections = vec![];19let mut preamble = vec![];20let mut cur_section = None;2122let mut has_bom = false;2324for line in lines {25let line = line.unwrap();2627let line = if let Some(line) = line.strip_prefix('\u{feff}') {28has_bom = true;29line30} else {31&line32};3334if let Some('[') = line.chars().next() {35if let Some(right_bracket) = line.find(']') {36if let Some(section) = cur_section.take() {37sections.push(section);38}3940let name = &line[1..right_bracket];41cur_section = Some(Section {42name: name.to_owned(),43title_line: line.to_owned(), // preserves comment and bom44lines: vec![],45});46} else {47// Bad syntax48break;49}50} else if let Some(cur_section) = &mut cur_section {51cur_section.lines.push(line.to_owned());52} else {53preamble.push(line.to_owned());54}55}5657if let Some(section) = cur_section.take() {58sections.push(section);59}6061let ini = IniFile {62filename: PathBuf::from(filename),63preamble,64sections,65has_bom,66};67Ok(ini)68}6970pub fn write(&self) -> io::Result<()> {71let file = std::fs::File::create(&self.filename)?;72let mut file = std::io::LineWriter::new(file);7374// Write BOM75if self.has_bom {76file.write_all("\u{feff}".as_bytes())?;77}78for line in &self.preamble {79file.write_all(line.as_bytes())?;80file.write_all(b"\n")?;81}82for section in &self.sections {83file.write_all(section.title_line.as_bytes())?;84file.write_all(b"\n")?;85for line in §ion.lines {86file.write_all(line.as_bytes())?;87file.write_all(b"\n")?;88}89}9091Ok(())92}9394// Assumes alphabetical section order!95pub fn insert_section_if_missing(&mut self, section: &Section) -> bool {96// First, check if it's there.9798for iter_section in &self.sections {99if iter_section.name == section.name {100return false;101}102}103104// Then, find a suitable insertion spot105for (i, iter_section) in self.sections.iter_mut().enumerate() {106if iter_section.name > section.name {107println!("Inserting section {}", section.name);108self.sections.insert(i, section.clone());109return true;110}111}112// Reached the end for some reason? Add it.113// Also add an empty line to the previous section.114if let Some(last) = self.sections.last_mut() {115last.lines.push("".into());116}117self.sections.push(section.clone());118true119}120121pub fn get_section_mut(&mut self, section_name: &str) -> Option<&mut Section> {122self.sections123.iter_mut()124.find(|section| section.name == section_name)125}126}127128// Grabbed from a sample, a fast line reader iterator.129fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>130where131P: AsRef<Path>,132{133let file = File::open(filename)?;134use std::io::BufRead;135Ok(io::BufReader::new(file).lines())136}137138139