1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use windows_sys::Win32::{
    Foundation::HANDLE,
    System::Console::{
        GetConsoleScreenBufferInfo, GetConsoleWindow, GetStdHandle, CONSOLE_SCREEN_BUFFER_INFO,
        SMALL_RECT, STD_OUTPUT_HANDLE,
    },
    UI::HiDpi::GetDpiForWindow,
};

/// Struct to hold terminal size information in terms of width and height.
#[derive(Debug)]
pub struct TerminalSize {
    pub width: i32,  // Width of the terminal in pixels
    pub height: i32, // Height of the terminal in pixels
}

/// Struct to hold font size information in terms of width and height.
#[derive(Debug)]
pub struct FontSize {
    pub width: i32,  // Width of a single character in pixels
    pub height: i32, // Height of a single character in pixels
}

/// Enum to represent possible errors that can occur while getting terminal or font size.
#[derive(Debug)]
pub enum TerminalError {
    NoStdHandle,         // Standard output handle not found
    NoScreenBufferInfo,  // Failed to retrieve console screen buffer information
    UnsupportedDpi,      // DPI setting is unsupported (not 96, 120, or 144)
}

/// This function retrieves the font size used by the terminal in pixels.
/// 
/// ## Assumptions:
/// - The font size is set to 12 points, and the font type is "Consolas".
/// - No zooming in or out has been done.
/// - The DPI is set to either 100%, 125%, or 150% scaling (175% is not supported).
/// 
/// ## Returns:
/// - `Ok(FontSize)` with the font width and height in pixels.
/// - `Err(TerminalError)` if there's an issue obtaining the standard handle or the DPI is unsupported.
///
/// ## Note:
/// - The DPI values used are approximations for common scaling settings:
///   - 96 DPI (100% scaling)
///   - 120 DPI (125% scaling)
///   - 144 DPI (150% scaling)
pub fn get_size_of_the_font() -> Result<FontSize, TerminalError> {
    unsafe {
        let h_console: HANDLE = GetStdHandle(STD_OUTPUT_HANDLE);
        if h_console.is_null() {
            return Err(TerminalError::NoStdHandle);
        }
        let pixel_size = match GetDpiForWindow(GetConsoleWindow()) {
            96 => FontSize {
                width: 9,
                height: 20
            },
            120 => FontSize {
                width: 12,
                height: 25
            },
            144 => FontSize {
                width: 14,
                height: 32
            },
            _ => return Err(TerminalError::UnsupportedDpi)
        };
        return Ok(pixel_size);
    }
}

/// This function retrieves the size of the terminal window in pixels.
/// 
/// ## Assumptions:
/// - The font size is set to 12 points, and the font type is "Consolas".
/// - No zooming in or out has been done.
/// - The DPI is set to either 100%, 125%, or 150% scaling (175% is not supported).
/// 
/// ## Returns:
/// - `Ok(TerminalSize)` with the terminal's width and height in pixels.
/// - `Err(TerminalError)` if there's an issue obtaining the standard handle, retrieving screen buffer info, or the DPI is unsupported.
///
/// ## Note:
/// - The DPI values used are approximations for common scaling settings:
///   - 96 DPI (100% scaling)
///   - 120 DPI (125% scaling)
///   - 144 DPI (150% scaling)
pub fn get_size_of_the_terminal() -> Result<TerminalSize, TerminalError> {
    unsafe {
        let h_console: HANDLE = GetStdHandle(STD_OUTPUT_HANDLE);
        if h_console.is_null() {
            return Err(TerminalError::NoStdHandle);
        }

        let mut info = CONSOLE_SCREEN_BUFFER_INFO {
            dwSize: windows_sys::Win32::System::Console::COORD { X: 0, Y: 0 },
            dwCursorPosition: windows_sys::Win32::System::Console::COORD { X: 0, Y: 0 },
            wAttributes: 0,
            srWindow: SMALL_RECT {
                Left: 0,
                Top: 0,
                Right: 0,
                Bottom: 0,
            },
            dwMaximumWindowSize: windows_sys::Win32::System::Console::COORD { X: 0, Y: 0 },
        };
        if GetConsoleScreenBufferInfo(h_console, &mut info) == 0 {
            return Err(TerminalError::NoScreenBufferInfo);
        }
        let pixel_size = match GetDpiForWindow(GetConsoleWindow()) {
            96 => TerminalSize {
                width: 9 * info.dwSize.X as i32,
                height: 20 * info.dwSize.Y as i32,
            },
            120 => TerminalSize {
                width: 12 * info.dwSize.X as i32,
                height: 25 * info.dwSize.Y as i32,
            },
            144 => TerminalSize {
                width: 14 * info.dwSize.X as i32,
                height: 32 * info.dwSize.Y as i32
            },
            _ => return Err(TerminalError::UnsupportedDpi)
        };
        return Ok(pixel_size);
    }
}