Skip to content

Commit

Permalink
Implement experimental Sindarin (Mode of Gondor) support
Browse files Browse the repository at this point in the history
  • Loading branch information
Yaulendil committed Mar 30, 2021
1 parent cb5a091 commit d1fa25f
Show file tree
Hide file tree
Showing 7 changed files with 591 additions and 34 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "tengwar"
description = "Transcribe romanized text into J.R.R. Tolkien's Tengwar."
version = "0.1.0"
version = "0.2.0"

authors = ["Yaulendil <davarice@protonmail.com>"]
repository = "https://github.com/yaulendil/tengwar-rs"
Expand Down
121 changes: 102 additions & 19 deletions src/characters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ mod _vowels {
pub const TEHTA_I: Tehta = Tehta::basic('');
pub const TEHTA_O: Tehta = Tehta::basic('');
pub const TEHTA_U: Tehta = Tehta::basic('');
pub const TEHTA_Y: Tehta = Tehta::basic('');
}


Expand All @@ -80,6 +81,7 @@ mod _vowels {
pub const TEHTA_I: Tehta = Tehta::with_double('');
pub const TEHTA_O: Tehta = Tehta::with_double('');
pub const TEHTA_U: Tehta = Tehta::with_double('');
pub const TEHTA_Y: Tehta = Tehta::basic('');
}


Expand All @@ -92,6 +94,7 @@ mod _vowels {
pub const TEHTA_I: Tehta = Tehta::with_variant('', '');
pub const TEHTA_O: Tehta = Tehta::with_variant('', '');
pub const TEHTA_U: Tehta = Tehta::with_variant('', '');
pub const TEHTA_Y: Tehta = Tehta::basic('');
}


Expand Down Expand Up @@ -263,6 +266,12 @@ impl Tehta {
f.write_char(self.base)
}
}

/// Returns true if the long variant of this Tehta would be written with the
/// extended "Ára" Telco.
pub const fn uses_ara(&self) -> bool {
!self.double && self.long.is_none()
}
}


Expand Down Expand Up @@ -320,10 +329,17 @@ pub struct Glyph {
/// If Silmë follows another tengwa, the base character may be modified by
/// a sa-rincë instead.
pub silme: bool,
/// A labialized consonant is represented by an additional diacritic.
pub nasal: bool,
/// A labialized consonant is represented by an additional diacritic.
pub labial: bool,
/// A palatalized vowel is represented by an additional diacritic.
pub palatal: bool,
pub long_cons: bool,
pub long_vowel: bool,
/// Indicates whether a long vowel using the extended "Ára" Telco should be
/// placed before this glyph.
pub long_first: bool,
}


Expand All @@ -333,9 +349,12 @@ impl Glyph {
cons: None,
vowel: None,
silme: false,
nasal: false,
labial: false,
palatal: false,
long_cons: false,
long_vowel: false,
long_first: false,
}
}

Expand Down Expand Up @@ -363,6 +382,16 @@ impl Glyph {
}
}

pub const fn with_labial(mut self) -> Self {
self.labial = true;
self
}

pub const fn with_nasal(mut self) -> Self {
self.nasal = true;
self
}

pub const fn with_palatal(mut self) -> Self {
self.palatal = true;
self
Expand Down Expand Up @@ -403,30 +432,84 @@ impl Glyph {

impl fmt::Display for Glyph {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let Glyph { cons, vowel, silme, palatal, long_cons, long_vowel } = self;
let (base, rince): (char, bool) = match cons {
Some(ch) => self.get_base(*ch),
None => (carrier(*long_vowel), *silme),
};
let Glyph {
cons, vowel, silme,
nasal, labial, palatal,
long_cons, long_vowel, long_first,
} = self;

let vowel_first: bool = *long_first
&& (*long_vowel || *labial)
&& cons.is_some();

if vowel_first {
if let Some(vowel) = vowel {
if vowel.uses_ara() && *long_vowel {
vowel.write(f, true)?;
} else {
f.write_char(carrier(*long_vowel))?;
vowel.write(f, false)?;
}
}

f.write_char(base)?;
let (base, rince) = self.get_base(cons.unwrap());

if *long_cons {
f.write_char(MOD_LONG_CONS)?;
}
f.write_char(base)?;

if *palatal {
f.write_char(MOD_PALATAL)?;
}
if *nasal {
f.write_char(MOD_NASAL)?;
}

if let Some(vowel) = vowel {
vowel.write(f, *long_vowel && cons.is_some())?;
}
if *long_cons {
f.write_char(MOD_LONG_CONS)?;
}

if rince {
f.write_char(mod_rince(base))?;
}
if *labial {
f.write_char(MOD_LABIAL)?;
}

if *palatal {
f.write_char(MOD_PALATAL)?;
}

Ok(())
if rince {
f.write_char(mod_rince(base))?;
}

Ok(())
} else {
let (base, rince): (char, bool) = match cons {
Some(ch) => self.get_base(*ch),
None => (carrier(*long_vowel), *silme),
};

f.write_char(base)?;

if *nasal {
f.write_char(MOD_NASAL)?;
}

if *long_cons {
f.write_char(MOD_LONG_CONS)?;
}

if *labial {
f.write_char(MOD_LABIAL)?;
}

if *palatal {
f.write_char(MOD_PALATAL)?;
}

if let Some(vowel) = vowel {
vowel.write(f, *long_vowel && cons.is_some())?;
}

if rince {
f.write_char(mod_rince(base))?;
}

Ok(())
}
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
pub mod characters;
pub mod etc;
pub mod quenya;
pub mod sindarin;

pub use characters::{int_10, int_12};
pub use quenya::Quenya;
pub use sindarin::Sindarin;
use std::{borrow::Cow, fmt::{self, Write}};


Expand Down
20 changes: 10 additions & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ use std::{
io::{BufRead, stdin, stdout, Write},
process::exit,
};
use tengwar::{Quenya, Rules};
use tengwar::{Quenya, Rules, Sindarin};


#[derive(Debug)]
enum Mode {
Quenya,
/*Sindarin,*/
Sindarin,
/*Beleriand,*/
/*English,*/
}
Expand All @@ -20,12 +20,12 @@ impl Mode {

const fn new(
quenya: bool,
/*sindarin: bool,*/
sindarin: bool,
/*beleriand: bool,*/
/*english: bool,*/
) -> Result<Mode, u32> {
let n = quenya as u32
/*+ sindarin as u32*/
+ sindarin as u32
/*+ beleriand as u32*/
/*+ english as u32*/;

Expand All @@ -35,8 +35,8 @@ impl Mode {
Err(n)
} else if quenya {
Ok(Mode::Quenya)
/*} else if sindarin {
Ok(Mode::Sindarin)*/
} else if sindarin {
Ok(Mode::Sindarin)
/*} else if beleriand {
Ok(Mode::Beleriand)*/
/*} else if english {
Expand All @@ -49,7 +49,7 @@ impl Mode {
fn rules<T: AsRef<str>>(&self) -> fn(T) -> String {
match self {
Mode::Quenya => { Quenya::transcribe }
/*Mode::Sindarin => { Sindarin::transcribe }*/
Mode::Sindarin => { Sindarin::transcribe }
/*Mode::Beleriand => { Beleriand::transcribe }*/
/*Mode::English => { English::transcribe }*/
}
Expand Down Expand Up @@ -77,9 +77,9 @@ struct Command {
#[argh(switch, short = 'q')]
quenya: bool,

/*/// transliterate in the Sindarin mode
/// transliterate in the Sindarin mode (experimental)
#[argh(switch, short = 's')]
sindarin: bool,*/
sindarin: bool,

/*/// transliterate in the Mode of Beleriand
#[argh(switch, short = 'b')]
Expand All @@ -99,7 +99,7 @@ impl Command {
const fn mode(&self) -> Result<Mode, u32> {
Mode::new(
self.quenya,
/*self.sindarin,*/
self.sindarin,
/*self.beleriand,*/
/*self.english,*/
)
Expand Down
Loading

0 comments on commit d1fa25f

Please sign in to comment.