Translate

2021-04-07

Learning Rust. Part 11. Training project, editor. The ingenious inline editing in "comment" mode. Marvelous!


The two functions (shown in Part 7) that comprise the code for the "comment" mode is the comment_start() and the t-get(). Inline editing must be added to those. Line editing in the other functions is provided by the console.

Since this is the clunkiest editor in human memory, the inline editing will consist of:
deleting the last character entered and printing out the remainder after a space, on the same line. It looks ridiculous but it works.

If the line is a long one, one has to copy the correct part of the line, if any, into the Ctrl-c buffer first, delete it and the error, make correction and then Ctrl-v back the copied part.

(Opinion: I really hate users! On the other hand, if I had to write a complete editor I wouldn't have finished until Christmas and that would be magnificently useless since I have Kate, already.)

The delete character used is also known as "Backspace", in decimal: 127. I try a new method of explaining changes. One or more may exist of a certain number, the reasons in that case are the same.

 fn comment_start(fname_ini:String) {
    let fname_slice: &str = &fname_ini;
    let mut s = String::new();
    let a:&str = "1";
    let b:&str = "1";

    while a == "1" && b == "1" {
        s = t_get(s,fname_slice.to_string());
        if s.len()<1 {                                                        
               //  (1, three lines.
            comment_start(fname_slice.to_string());
        }
        let n1 = s.len()-1;
        let ch1 = s.chars().nth(n1).unwrap();


        s=t_get(s,fname_slice.to_string());
        if s.len()<1 {                                                                       //  (1, three lines. [one more of same]
            comment_start(fname_slice.to_string());
        }
        let n2 = s.len()-1;
        let ch2 = s.chars().nth(n2).unwrap();

        if (ch1 == '*') && (ch2 == '/') {                                       // if true, foreboding end of comment
            let s=add_comment_tags(s);                                        // (2, tags denoting start & end, comments
            let f = open_file(fname_slice.to_string());
            write_file(s,f);
            print!("\n");
            list(fname_slice.to_string());
            io::stdout().flush().unwrap();

            exit(0);                                                                            // back to main()
        }

        if ch2 == '*' {
             s=t_get(s,fname_slice.to_string());
            if s.len()<1 {
                                                                      //  (1, three lines. Surprise! Third one!
                comment_start(fname_slice.to_string());
            }
            let n3 = s.len()-1;
            let ch3 = s.chars().nth(n3).unwrap();
            if ch3 == '/' {                                                                      // if true, foreboding end of comment
            let s=add_comment_tags(s);                                            // (2, same thing as last (2, same reason
            let f = open_file(fname_slice.to_string());
            write_file(s,f);
            list(fname_slice.to_string());           

            exit(0);                                                                                // back to main()    

            }

        }

    }

}

// shortening comment_start() by not repeating the same code twice, this function does.
fn add_comment_tags(mut s:String) -> std::string::String {
    let prefix:String = "\n/* ".to_string();
    let suffix:String = "\n".to_string();
    s = prefix + &s + &suffix;
    s
}

fn t_get(mut s:String, fname_ini:String) -> String {
        let mut raw = getachar();
//        print!("{}",raw[0]);                                                    // activated, shows dec value of char
        if raw[0] > 127 {                                                            // Oh no! A non-ASCII charcter!
            raw = [7; 1];                                                              // still thinking of a better way to deal with it
        }
        if raw[0] == 127 {                                                         // (3, eight lines
            if s.len()<1 {
                comment_start(fname_ini);
            }
            s.pop();
            print!(" {}",s);
            return s;
        };

        let  mybyte = str::from_utf8(&raw).unwrap();
        s.push_str(&mybyte);
        let n1 = s.len()-1;                                                        // (4, four lines
        let ch1 = s.chars().nth(n1).unwrap();
        print!("{}",ch1);
        io::stdout().flush().unwrap();

        s
}

Lets start with what differs compared to whats in the Part 7 version. The comment_start() function:

(1 
Added;

        if s.len()<1 {                                                        // out of characters! None left!
            comment_start(fname_slice.to_string());    // restart of this function
        }
When the user has deleted (backspaced) the whole sentence and then, to be absolutley sure here really did what he did, presses backspace again Ouch! On line south is this waiting to Panic the program:
        let n1 = s.len()-1;
When this executes I will try to subtract from a String with nothing in it, trying to get into memory cells not reserved for me. To stop that from happening, I violently call myself, making me start from the beinning, the cursor still left in the same position. The user will see nothing happening and start entering new things again, no problem. 

(2 Added;
    let s=add_comment_tags(s);
I decided to use "/*" and "*/" as comment tags in the .ini-file. Shortening the comment_start() by not repeating this code piece. Instead moved to the function add_comment_tags(). Clear as mud.

Lets have a look at t_get() function. Here some things reside that are missing in comment_start() and some that are added.
(3 Added;

        if raw[0] == 127 {
            if s.len()<1 {
                comment_start(fname_ini);
            }
            s.pop();
            print!(" {}",s);
            return s;                                                            // This return takes us back to command_start()!
        };
This where the editing magic happens, 127 is the backspace. If condition true AND there are no more character in "s", comment_start() is restarting. Cursor still in the same place, the user have no idea that this happened.
If the condition is false, the last char is popped off and the whole "s" is reprinted without it. Remember, we're not using this editor to write books. The user can happily continue to comment some more.

(4 Added;

        let n1 = s.len()-1; 
        let ch1 = s.chars().nth(n1).unwrap();
        print!("{}",ch1);
        io::stdout().flush().unwrap();

If we pass those both comparisons, the printing of the lonesome character is done here instead of via three print! statements sprinkled throughout command_start(). We have to get that char from the end of "s", the same way as in comment-start() so these have been added for that purpose.

General comment: my war against the compiler subsides a bit. The pain lessens with it. A glimmer of hope emerges at the horizon...

                Note vertical copyright. I totally don't use it for commercial purposes! Don't hit me!



That's all folks!

To be continued...

Inga kommentarer:

Skicka en kommentar