ncurses: program exiting when arrow key pressed - ncurses

my question is exactly as the title says. My program exits right after I press an arrow up.
Here's my program:
pub fn main() !void {
_ = c.initscr();
defer _ = c.endwin();
var i: u32 = 0;
main_loop: while (true) : (i += 1) {
var key: c_int = undefined;
if (i != 0) {
key = c.getch();
switch (key) {
std.ascii.control_code.esc => break :main_loop,
c.KEY_UP => {
const dir = try std.fs.cwd().openIterableDir(cwd_path, .{});
_ = dir;
try putText(CWD_Y + 2, CWD_X + 2, "hahaha");
},
else => try putText(ERROR_Y, ERROR_X, "ERROR: pressed unhandled key"),
}
}
try updateCwd();
try putText(CWD_Y, CWD_X, cwd_path);
}
}
Thanks

On most terminals, KEY_UP corresponds to an escape sequence. If you want your program to translate that escape sequence into a key-code, use the keypad function, e.g., calling this after initscr:
c.keypad(1);

Related

How can I add a global keydown event listener in Dioxus)?

I'm currently trying out dioxus for rust, and I'm trying to figure out how to handle a global keyboard down event.
I want to use the arrow keys to move images back and forth:
Here's my code so far:
use dioxus::{events::*, prelude::*};
use log::{info, LevelFilter};
/**
* Specify <link data-trunk rel="copy-dir" href="src/assets" />
* in the index.html to copy the files!!
*
* You'll see them in the dist directory!
*/
fn main() {
dioxus_logger::init(LevelFilter::Info).expect("failed to init logger");
dioxus::web::launch(app);
}
fn app(cx: Scope) -> Element {
let mut index = use_state(&cx, || 1);
let change_evt = move |evt: KeyboardEvent| match evt.key.as_str() {
"ArrowRight" => index += 1,
"ArrowLeft" => index -= 1,
_ => {}
};
let url = format!("/assets/img/wallpaper/1042/0{}.jpg", index);
cx.render(rsx!(img {
src: "{url}",
onkeydown: change_evt,
}))
}
In JavaScript would've been something like
document.addEventListener('keydown', (evt) => {
// Do magic
}
I've tried following the calculator example but can't get it to work.
Any ideas?
onkeydown does not seem to work as a callback passed to an image. Wrap it in a div.
I placed an extra button there because, for some reason, the keyboard event callbacks did not register until I interacted with the app somehow (tried it in the browser).
fn app(cx: Scope) -> Element {
let mut index = use_state(&cx, || 1);
let change_evt = move |evt: KeyboardEvent| {
log::info!("{index}{}", evt.key);
match evt.key.as_str() {
"ArrowRight" => index += 1,
"ArrowLeft" => index -= 1,
_ => {}
}
};
let url = format!("/assets/img/wallpaper/1042/0{}.jpg", index);
cx.render(rsx!(
img {
src: "{url}",
}
div {
class: "display",
onkeydown: change_evt,
button {
class: "but",
onclick: move |evt| {
println!("{evt:?}");
info!("{evt:?}");
},
"Press me!"
},
},
))
}

Refactoring variable assignment thru if let block with Enum

I'm working with the code below, which works, but is clearly not a very clever or efficient way to write a value to res.
let mut res = "";
if let Video(n) = res_info { // res_info represents reference to &Settings type
if n.pixel_width > 1920{
res = "2160p";
}
else{
res = "1080p";
}
}
Printing res_info would yield the following:
Video(Video { pixel_width: 1920, pixel_height: 1080})
The following code seems to be close, however it's not assigning &str to res. I would much prefer a codeblock like this, in which res is only declared once.
let res = if let Video(n) = res_info {
if n.pixel_width > 1920 {
"2160p";
}
else{
"1080p";
}
};
As per the unit documentation
The semicolon ; can be used to discard the result of an expression at the end of a block, making the expression (and thus the block) evaluate to ()
Removing the semicolon should stop value from being discarded so the &str is resolved from the if blocks.
let res = if let Video(n) = res_info {
if n.pixel_width > 1920{
"2160p"
} else{
"1080p"
}
}else{
panic!("res_info is not a Video")
};
or with a match statement might be cleaner
let res = match res_info {
Video(n) if n.pixel_width > 1920 => "2160p",
Video(n) => "1080p",
_ => panic!("res_info is not a Video")
};

How to get argument of a variant?

Having these enums
pub enum Symbol {
X,
O,
}
pub enum CellContent {
Move(Symbol),
Empty,
}
and
let cell_content = CellContent::Move(Symbol::X);
how can I get the Symbol ? Of course if it's of variant Move(Symbol)
This doesn't work
if cell_0_0 == Move(a_symbol) {
return Some(a_symbol);
}
I cannot also do the following because I must do nothing (code must continue evaluation); and the following doesn't even compile at all !
match cell_0_0 {
Move(symbol) => return symbol;
_ => // do nothing;
}
// code must go on to check further conditions
| I still have some problem with basic syntax of rust, so I'm experiencing making some basic programs
So question is
How to
check if my variable is a variant of Move(Symbol)
if yes return (a copy of) symbol
else do nothing, so code can go on and do more checks
?
Edit 1: Full (not working) code
pub fn some_one_win(&self) -> Option<Symbol> {
let cell_0_0: CellContent = self.table[0][0];
let cell_0_1: CellContent = self.table[0][1];
let cell_0_2: CellContent = self.table[0][2];
if cell_0_0 == cell_0_1 && cell_0_0 == cell_0_2 {
match cell_0_0 {
Move(symbol) => return symbol;
_ => // how to 'do nothing' here ?;
}
}
let cell_1_0: CellContent = self.table[1][0];
let cell_1_1: CellContent = self.table[1][1];
let cell_1_2: CellContent = self.table[1][2];
if cell_1_0 == cell_1_1 && cell_1_0 == cell_1_2 {
match cell_1_0 {
Move(symbol) => return symbol;
_ => // how to 'do nothing' here ?;
}
}
... and so on ..
}
I cannot also do the following because I must do nothing (code must continue evaluation); and the following doesn't even compile at all !
match cell_0_0 {
Move(symbol) => return symbol;
_ => // do nothing;
}
You can do that, if you get the syntax right:
match cell_0_0 {
CellContent::Move(symbol) => {
return Some(symbol);
}
_ => {} // do nothing
}
But as PitaJ mentioned, when there’s only one pattern plus _, the if let construct is usually a cleaner alternative:
if let CellContent::Move(symbol) = cell_0_0 {
return Some(symbol);
}

shouldInteractWithURL called twice on 3d touch

Below is the issue that i am trying to fix. I have a textView whose text is an attributed string with link attribute. On clicking the link, i should go to other screen. So, I am performing that screen navigation on shouldInteractWithURL() delegate method of the textView. Everything works fine except on force touching the textView, the next page is loading twice. That means shouldInteractWithURL() is called twice on force tap. I fixed it by checking the stack of the view controllers and if the last VC is the one that is about to load, I am returning from there. But, I wanted to know if there is any other solution other than this. Below is the code snippet
textView.text = ""
guard var str = myStr else {
return nil
}
let linkAttribute = [NSLinkAttributeName: NSURL(string: "")!]
var attributedStr:NSMutableAttributedString?
if delay {
str += " "
attributedStr = NSMutableAttributedString(string: str)
let ctaStr = kSuccessStr
let ctaAttributedString = NSAttributedString(string: ctaStr, attributes: linkAttribute)
attributedStr!.appendAttributedString(ctaAttributedString)
} else {
let ctaStr = kFailedStr
attributedStr = NSMutableAttributedString(string: ctaStr, attributes: linkAttribute)
}
textView.linkTextAttributes = [NSForegroundColorAttributeName: UIColor.grayColor()]
textView.attributedText = attributedStr
textView.delegate = thisTableViewDelegate
func textView(textView: UITextView, shouldInteractWithURL URL: NSURL, inRange characterRange: NSRange) -> Bool
{
if let textLink = textView.text
{
if (textLink.rangeOfString(str1) != nil) ||
(textLink.rangeOfString(str2) != nil)
{
showSignUpForm(self)
}
else
{
showSuccessfulForm()
}
}
return true
}
Use textView:shouldInteractWithURL:inRange:interaction: instead.
Check if interaction != UITextItemInteractionInvokeDefaultAction and return NO.
See https://developer.apple.com/reference/uikit/uitextviewdelegate/1618606-textview?language=objc
I handle only invokeDefaultAction and it works for me:
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
if interaction == .invokeDefaultAction {
//do some stuff
}
return false
}

Swap string case - swift

let str = "tHIS is A test"
let swapped_case = "This IS a TEST"
Swift noob here, how to do the second statement programatically?
This function works with all upper/lowercase characters
defined in Unicode, even those from "foreign" languages such as Ä or ć:
func swapCases(_ str : String) -> String {
var result = ""
for c in str.characters { // Swift 1: for c in str {
let s = String(c)
let lo = s.lowercased() //Swift 1 & 2: s.lowercaseString
let up = s.uppercased() //Swift 1 & 2: s.uppercaseString
result += (s == lo) ? up : lo
}
return result
}
Example:
let str = "tHIS is a test ÄöÜ ĂćŒ Α" // The last character is a capital Greek Alpha
let swapped_case = swapCases(str)
print(swapped_case)
// This IS A TEST äÖü ăĆœ α
Use switch statement in-range checks to determine letter case, and use NSString-bridged methods to convert accordingly.
let str = "tHIS is A test"
let swapped_case = "This IS a TEST"
func swapCase(string: String) -> String {
var swappedCaseString: String = ""
for character in string {
switch character {
case "a"..."z":
let uppercaseCharacter = (String(character) as NSString).uppercaseString
swappedCaseString += uppercaseCharacter
case "A"..."Z":
let lowercaseCharacter = (String(character) as NSString).lowercaseString
swappedCaseString += lowercaseCharacter
default:
swappedCaseString += String(character)
}
}
return swappedCaseString
}
swapCase(str)
I'm a bit too late but this works too :-)
let str = "tHIS is A test"
var res = ""
for c in str {
if contains("ABCDEFGHIJKLMNOPQRSTUVWXYZ", c) {
res += "\(c)".lowercaseString
} else {
res += "\(c)".uppercaseString
}
}
res
In Swift 5 I achieved it by creating a function which iterates through each character of the string, and using string methods to change each character I appended each character back into a new variable:
func reverseCase(string: String) -> String {
var newCase = ""
for char in string {
if char.isLowercase {
newCase.append(char.uppercased())
}
else if char.isUppercase {
newCase.append(char.lowercased())
}
else {
newCase.append(char)
}
}
return newCase
}
Then just pass your string through to the function when you call it in a print statement:
print(reverseCase(string: str))
You already have plenty of good succinct answers but here’s an over-elaborate one for fun.
Really this is a job for map – iterate over a collection (in this case String) and do a thing to each element (here, each Character). Except map takes any collection, but only gives you back an array, which you’d have to then turn into a String again.
But here’s a version of map that, given an extensible collection, gives you back that same kind of extensible collection.
(It does have the limitation of needing both collections to contain the same type, but that’s fine for strings. You could make it return a different type, but then you’d have to tell it which type you wanted i.e. map(s, transform) as String which would be annoying)
func map<C: ExtensibleCollectionType>(source: C, transform: (C.Generator.Element) -> C.Generator.Element) -> C {
var result = C()
for elem in source {
result.append(transform(elem))
}
return result
}
Then to write the transform function, first here’s an extension to character similar to the other answers. It does seem quite unsatisfying that you have to convert to a string just to uppercase a character, is there really no good (international characterset-friendly) way to do this?
extension Character {
var uppercaseCharacter: Character {
let s = String(self).uppercaseString
return s[s.startIndex]
}
var lowercaseCharacter: Character {
let s = String(self).lowercaseString
return s[s.startIndex]
}
}
And the function to flip the case. What I wonder is whether this pattern matching is international-friendly. It seems to be – "A"..."Z" ~= "Ä" returns true.
func flipCase(c: Character) -> Character {
switch c {
case "A"..."Z":
return c.lowercaseCharacter
case "a"..."z":
return c.uppercaseCharacter
default:
return c
}
}
Finally:
let s = map("Hello", flipCase)
// s is a String = "hELLO"
I hope this helps. inputString and resultString are the input and output respectively.
let inputString = "Example"
let outputString = inputString.characters.map { (character) -> Character in
let string = String(character)
let lower = string.lowercased()
let upper = string.uppercased()
return (string == lower) ? Character(upper) : Character(lower)
}
let resultString = String(outputString)

Resources