# NEdit auto-indent and type-in macros for O'Caml. # By Nathaniel Gray # 5/21/2002 # Version 0.6 -- fixed to work in the presence of hard tabs. # # Drop me an e-mail if you use this stuff! I suspect that nobody ever will... # # The type-in macro just automatically dedents '|' if it is typed as the # first character on a line. This follows the style of OCaml indentation that # I've seen most often. Note that it doesn't do this if the previous line # also starts with a '|', since in that case the smart-indent macros should # already have left the cursor aligned with the previous '|'. # # The auto-indent macro increases the indent if the last word (non-ws block) is # in the $indent_words array. It adds two extra characters if the current line # begins with a |. # INSTALLATION INSTRUCTIONS: # 1. Put this file wherever you keep your NEdit macros. I keep mine # in a directory called $HOME/nedit_macros # 2. Start NEdit and go to # Preferences | Default Settings | Auto Indent | Program Smart Indent... # 3. Put this in the first text field (changing the file name if needed): # load_macro_file(getenv("HOME") "/nedit_macros/ocaml_indent_macros.nm") # 4. Put this in the second text field: # return ocaml_indent( $1 ) # 5. Put this in the third text field: # ocaml_typein( $1, $2 ) # # That should do it. Hit "OK" and load an O'Caml file. Don't forget to # Save your preferences too! # These macros increase the indentation after any line that ends with one of # these words. Dedents are basically impossible to figure out without a real # parser, so you have to do them manually. $ocaml_indent_words["->"] = 1 $ocaml_indent_words["try"] = 1 $ocaml_indent_words["with"] = 1 $ocaml_indent_words["begin"] = 1 $ocaml_indent_words["do"] = 1 $ocaml_indent_words["="] = 1 $ocaml_indent_words["then"] = 1 $ocaml_indent_words["else"] = 1 $ocaml_indent_words["struct"] = 1 $ocaml_indent_words["sig"] = 1 $ocaml_indent_words["object"] = 1 $ocaml_indent_words["function"] = 1 $pipe_dedent = 2 # The number of columns to dedent '|' characters. This is # assumed to be less than one tab character. # Type-in macro for dedenting | chars define ocaml_typein { # Only take action when | is typed if( $2 != "|" ) { return } else { # Corner cases that might cause trouble if( $line == 1 || $column < $pipe_dedent ) { #t_print( "line or column too small: " $line " " $column "\n" ) return } # Find out if it's the first char on the line beg_of_line = search("^\\s+", $1, "regex", "backward") if( $search_end < $1 ) { #t_print( "not the first char: '" $search_end "' < '" $1 "'\n" ) #t_print( "isfirst: " isfirst "\n" ) return } #t_print( "Is the first char. WS from " isfirst " to " $search_end \ # " and | is at " $1 "\n" ) # Find out if there's a | starting the previous line beg_of_line2 = search("^", beg_of_line-1, "regex", "backward") isfirst2 = search("^\\s*\\|", beg_of_line-1, "regex", "backward") if( isfirst2 == beg_of_line2 ) { # Don't adjust, smart indent already matched the prev. pipe #t_print( "Already matched by auto-indent\n" ) return } # back the | up $pipe_dedent spaces # try not to screw up if there are tabs insert_pos = $1 str = " " for( i = insert_pos-1; i >= insert_pos-$pipe_dedent; i-- ) { ch = get_character( i ) if (ch == "\t") { # Replace the tab with spaces orig_cursor_pos = $cursor set_cursor_pos( i+1 ) end_tab = $column set_cursor_pos( i ) beg_tab = $column set_cursor_pos( orig_cursor_pos ) tab_width = end_tab - beg_tab replace_range(i, i+1, substring(str, 0, tab_width)) insert_pos += tab_width - 1 } else if (ch != " ") { # Bail out on non-ws (shouldn't be possible, but...) return } } # Now delete $pipe_dedent spaces before the insert position replace_range(insert_pos-$pipe_dedent, insert_pos, "") #t_print( "Done it\n" ) } } define ocaml_indent { # Look backwards for the last chunk of non-whitespace. beg_of_line = search("^", $1, "regex", "backward") beg_word = search("(?:\\s|^)\\S+", $1, "regex", "backward") if (beg_word < 0 || beg_word < beg_of_line) { #t_print( "no last word\n" ) return -1 } end_word = min($search_end, $1) last_word = get_range( beg_word, end_word ) if (search_string(last_word, "\\s", 0, "regex") >= 0) last_word = get_range( beg_word+1, end_word ) if (!(last_word in $ocaml_indent_words)) { #t_print( "last word not in dict: " last_word "\n" ) return -1 } def_indent = measureIndent( $1 ) i = def_indent + defaultIndent("default") if( get_character( startOfLine($1) + def_indent ) == "|" ) i += $pipe_dedent return i }