use crate::{Result, brlapi_call};
use brlapi_sys::*;
use libc::wchar_t;
use std::ffi::CString;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CursorPosition {
Leave,
Off,
At(u32),
}
impl From<CursorPosition> for i32 {
fn from(pos: CursorPosition) -> i32 {
match pos {
CursorPosition::Leave => BRLAPI_CURSOR_LEAVE,
CursorPosition::Off => BRLAPI_CURSOR_OFF as i32,
CursorPosition::At(position) => position as i32,
}
}
}
#[derive(Debug)]
pub struct TextWriter<'a> {
tty_mode: &'a crate::TtyMode<'a>,
}
impl<'a> TextWriter<'a> {
pub fn from_tty_mode(tty_mode: &'a crate::TtyMode<'a>) -> Self {
Self { tty_mode }
}
#[doc(hidden)]
pub fn new(tty_mode: &'a crate::TtyMode<'a>) -> Self {
Self::from_tty_mode(tty_mode)
}
pub fn write_text(&self, text: &str) -> Result<()> {
self.write_with_cursor(text, CursorPosition::Leave)
}
pub fn write_with_cursor(&self, text: &str, cursor: CursorPosition) -> Result<()> {
let c_text = CString::new(text)?;
brlapi_call!(unsafe {
brlapi__writeText(
self.tty_mode.connection().handle_ptr(),
cursor.into(),
c_text.as_ptr(),
)
})?;
Ok(())
}
pub fn write_notification(&self, text: &str) -> Result<()> {
self.write_with_cursor(text, CursorPosition::Off)
}
pub fn write_contracted(&self, text: &str, table: &str, cursor: CursorPosition) -> Result<()> {
let translator = liblouis::Translator::new();
let contracted_text = translator.translate_string(table, text)?;
self.write_with_cursor(&contracted_text, cursor)
}
pub fn write_contracted_with_cursor_tracking(
&self,
text: &str,
table: &str,
cursor_pos: usize,
) -> Result<usize> {
let translator = liblouis::Translator::new();
let (contracted_text, new_cursor_pos) =
translator.translate_string_with_cursor(table, text, cursor_pos)?;
self.write_with_cursor(&contracted_text, CursorPosition::At(new_cursor_pos as u32))?;
Ok(new_cursor_pos)
}
pub fn write_contracted_user_preference(
&self,
text: &str,
cursor: CursorPosition,
) -> Result<()> {
let connection = self.tty_mode.connection();
let table = connection.user_contraction_table()?;
self.write_contracted(text, &table, cursor)
}
pub fn write_contracted_en_us_g2(&self, text: &str, cursor: CursorPosition) -> Result<()> {
self.write_contracted(text, "en-us-g2.ctb", cursor)
}
pub fn write_contracted_en_gb_g2(&self, text: &str, cursor: CursorPosition) -> Result<()> {
self.write_contracted(text, "en-gb-g2.ctb", cursor)
}
pub fn write_with_table(
&self,
table: &liblouis::Table,
text: &str,
cursor: CursorPosition,
) -> Result<()> {
let translator = liblouis::Translator::new();
let contracted_text = table.translate(&translator, text)?;
self.write_with_cursor(&contracted_text, cursor)
}
pub fn write_computer_braille(&self, text: &str, cursor: CursorPosition) -> Result<()> {
self.write_with_cursor(text, cursor)
}
pub fn write_unicode(&self, text: &str, cursor: CursorPosition) -> Result<()> {
let wide_text: Vec<wchar_t> = text
.chars()
.map(|c| c as wchar_t)
.chain(std::iter::once(0))
.collect();
brlapi_call!(unsafe {
brlapi__writeWText(
self.tty_mode.connection().handle_ptr(),
cursor.into(),
wide_text.as_ptr(),
)
})?;
Ok(())
}
pub fn write_dots(&self, dots: &[u8]) -> Result<()> {
brlapi_call!(unsafe {
brlapi__writeDots(self.tty_mode.connection().handle_ptr(), dots.as_ptr())
})?;
Ok(())
}
pub fn tty_mode(&self) -> &crate::TtyMode<'a> {
self.tty_mode
}
pub fn connection(&self) -> &crate::Connection {
self.tty_mode.connection()
}
}
pub mod util {
use super::*;
use crate::Connection;
pub fn send_message(text: &str) -> Result<()> {
let connection = Connection::open()?;
write_message(&connection, text)
}
pub fn write_message(connection: &Connection, text: &str) -> Result<()> {
use crate::TtyMode;
let (tty_mode, _) = TtyMode::enter_auto(connection, None)?;
let writer = tty_mode.writer();
writer.write_text(text)
}
pub fn write_message_with_cursor(
connection: &Connection,
text: &str,
cursor: CursorPosition,
) -> Result<()> {
use crate::TtyMode;
let _ = CString::new(text)?;
let (tty_mode, _) = TtyMode::enter_auto(connection, None)?;
let writer = tty_mode.writer();
writer.write_with_cursor(text, cursor)
}
pub fn write_notification(connection: &Connection, text: &str) -> Result<()> {
write_message_with_cursor(connection, text, CursorPosition::Off)
}
pub fn write_contracted_message(
connection: &Connection,
text: &str,
table: &str,
) -> Result<()> {
use crate::TtyMode;
let (tty_mode, _) = TtyMode::enter_auto(connection, None)?;
let writer = tty_mode.writer();
writer.write_contracted(text, table, CursorPosition::Off)
}
pub fn send_contracted_message(text: &str) -> Result<()> {
let connection = Connection::open()?;
let table = connection.user_contraction_table()?;
write_contracted_message(&connection, text, &table)
}
pub fn send_contracted_message_en_us_g2(text: &str) -> Result<()> {
let connection = Connection::open()?;
write_contracted_message(&connection, text, "en-us-g2.ctb")
}
}