termsize.zig (3220B)
1 // Copyright (c) 2024 Doug Tangren 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining 4 // a copy of this software and associated documentation files (the 5 // "Software"), to deal in the Software without restriction, including 6 // without limitation the rights to use, copy, modify, merge, publish, 7 // distribute, sublicense, and/or sell copies of the Software, and to 8 // permit persons to whom the Software is furnished to do so, subject to 9 // the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be 12 // included in all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 // 22 // Repo: https://github.com/softprops/zig-termsize 23 // Modifications made by Brook Jeynes (https://github.com/brookjeynes) 24 25 const std = @import("std"); 26 const builtin = @import("builtin"); 27 const os = std.os; 28 29 /// Terminal size dimensions 30 pub const TermSize = struct { 31 /// Terminal width as measured number of characters that fit into a terminal horizontally 32 width: u16, 33 /// terminal height as measured number of characters that fit into terminal vertically 34 height: u16, 35 }; 36 37 /// ## example 38 /// 39 /// ```zig 40 /// const std = @import("std"); 41 /// const termSize = @import("termsize"); 42 /// 43 /// fn main(init: std.process.Init) !void { 44 /// std.debug.print( 45 /// "{any}", 46 /// termSize.termSize(std.Io.File.stdout(), init.io), 47 /// ); 48 /// } 49 /// ``` 50 pub fn termSize(file: std.Io.File, io: std.Io) !?TermSize { 51 const supports_ansi = file.supportsAnsiEscapeCodes(io) catch return null; 52 if (!supports_ansi) { 53 return null; 54 } 55 return switch (builtin.os.tag) { 56 .windows => blk: { 57 var buf: os.windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; 58 break :blk switch (os.windows.kernel32.GetConsoleScreenBufferInfo( 59 file.handle, 60 &buf, 61 )) { 62 os.windows.TRUE => TermSize{ 63 .width = @intCast(buf.srWindow.Right - buf.srWindow.Left + 1), 64 .height = @intCast(buf.srWindow.Bottom - buf.srWindow.Top + 1), 65 }, 66 else => error.Unexpected, 67 }; 68 }, 69 .linux, .macos => blk: { 70 var buf: std.posix.winsize = undefined; 71 break :blk switch (std.posix.errno( 72 std.posix.system.ioctl( 73 file.handle, 74 std.posix.T.IOCGWINSZ, 75 @intFromPtr(&buf), 76 ), 77 )) { 78 .SUCCESS => TermSize{ 79 .width = buf.col, 80 .height = buf.row, 81 }, 82 else => error.IoctlError, 83 }; 84 }, 85 else => error.Unsupported, 86 }; 87 }