@ -5,7 +5,7 @@ pub(crate) mod typed;
pub use dap ::* ;
pub use dap ::* ;
use helix_vcs ::Hunk ;
use helix_vcs ::Hunk ;
pub use lsp ::* ;
pub use lsp ::* ;
use tui ::text::Spans ;
use tui ::widgets::Row ;
pub use typed ::* ;
pub use typed ::* ;
use helix_core ::{
use helix_core ::{
@ -26,7 +26,6 @@ use helix_core::{
SmallVec , Tendril , Transaction ,
SmallVec , Tendril , Transaction ,
} ;
} ;
use helix_view ::{
use helix_view ::{
apply_transaction ,
clipboard ::ClipboardType ,
clipboard ::ClipboardType ,
document ::{ FormatterError , Mode , SCRATCH_BUFFER_NAME } ,
document ::{ FormatterError , Mode , SCRATCH_BUFFER_NAME } ,
editor ::{ Action , Motion } ,
editor ::{ Action , Motion } ,
@ -384,6 +383,7 @@ impl MappableCommand {
swap_view_down , "Swap with split below" ,
swap_view_down , "Swap with split below" ,
transpose_view , "Transpose splits" ,
transpose_view , "Transpose splits" ,
rotate_view , "Goto next window" ,
rotate_view , "Goto next window" ,
rotate_view_reverse , "Goto previous window" ,
hsplit , "Horizontal bottom split" ,
hsplit , "Horizontal bottom split" ,
hsplit_new , "Horizontal bottom split scratch buffer" ,
hsplit_new , "Horizontal bottom split scratch buffer" ,
vsplit , "Vertical right split" ,
vsplit , "Vertical right split" ,
@ -448,9 +448,16 @@ impl MappableCommand {
impl fmt ::Debug for MappableCommand {
impl fmt ::Debug for MappableCommand {
fn fmt ( & self , f : & mut std ::fmt ::Formatter < ' _ > ) -> std ::fmt ::Result {
fn fmt ( & self , f : & mut std ::fmt ::Formatter < ' _ > ) -> std ::fmt ::Result {
f . debug_tuple ( "MappableCommand" )
match self {
. field ( & self . name ( ) )
MappableCommand ::Static { name , .. } = > {
. finish ( )
f . debug_tuple ( "MappableCommand" ) . field ( name ) . finish ( )
}
MappableCommand ::Typable { name , args , .. } = > f
. debug_tuple ( "MappableCommand" )
. field ( name )
. field ( args )
. finish ( ) ,
}
}
}
}
}
@ -505,12 +512,16 @@ impl PartialEq for MappableCommand {
match ( self , other ) {
match ( self , other ) {
(
(
MappableCommand ::Typable {
MappableCommand ::Typable {
name : first_name , ..
name : first_name ,
args : first_args ,
..
} ,
} ,
MappableCommand ::Typable {
MappableCommand ::Typable {
name : second_name , ..
name : second_name ,
args : second_args ,
..
} ,
} ,
) = > first_name = = second_name ,
) = > first_name = = second_name & & first_args = = second_args ,
(
(
MappableCommand ::Static {
MappableCommand ::Static {
name : first_name , ..
name : first_name , ..
@ -863,7 +874,7 @@ fn align_selections(cx: &mut Context) {
changes . sort_unstable_by_key ( | ( from , _ , _ ) | * from ) ;
changes . sort_unstable_by_key ( | ( from , _ , _ ) | * from ) ;
let transaction = Transaction ::change ( doc . text ( ) , changes . into_iter ( ) ) ;
let transaction = Transaction ::change ( doc . text ( ) , changes . into_iter ( ) ) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
}
}
fn goto_window ( cx : & mut Context , align : Align ) {
fn goto_window ( cx : & mut Context , align : Align ) {
@ -1315,7 +1326,7 @@ fn replace(cx: &mut Context) {
}
}
} ) ;
} ) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
exit_select_mode ( cx ) ;
exit_select_mode ( cx ) ;
}
}
} )
} )
@ -1333,7 +1344,7 @@ where
( range . from ( ) , range . to ( ) , Some ( text ) )
( range . from ( ) , range . to ( ) , Some ( text ) )
} ) ;
} ) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
}
}
fn switch_case ( cx : & mut Context ) {
fn switch_case ( cx : & mut Context ) {
@ -1863,7 +1874,7 @@ fn global_search(cx: &mut Context) {
impl ui ::menu ::Item for FileResult {
impl ui ::menu ::Item for FileResult {
type Data = Option < PathBuf > ;
type Data = Option < PathBuf > ;
fn label ( & self , current_path : & Self ::Data ) -> Spans {
fn format ( & self , current_path : & Self ::Data ) -> Row {
let relative_path = helix_core ::path ::get_relative_path ( & self . path )
let relative_path = helix_core ::path ::get_relative_path ( & self . path )
. to_string_lossy ( )
. to_string_lossy ( )
. into_owned ( ) ;
. into_owned ( ) ;
@ -2003,6 +2014,10 @@ fn global_search(cx: &mut Context) {
let line_num = * line_num ;
let line_num = * line_num ;
let ( view , doc ) = current ! ( cx . editor ) ;
let ( view , doc ) = current ! ( cx . editor ) ;
let text = doc . text ( ) ;
let text = doc . text ( ) ;
if line_num > = text . len_lines ( ) {
cx . editor . set_error ( "The line you jumped to does not exist anymore because the file has changed." ) ;
return ;
}
let start = text . line_to_char ( line_num ) ;
let start = text . line_to_char ( line_num ) ;
let end = text . line_to_char ( ( line_num + 1 ) . min ( text . len_lines ( ) ) ) ;
let end = text . line_to_char ( ( line_num + 1 ) . min ( text . len_lines ( ) ) ) ;
@ -2158,7 +2173,7 @@ fn delete_selection_impl(cx: &mut Context, op: Operation) {
let transaction = Transaction ::change_by_selection ( doc . text ( ) , selection , | range | {
let transaction = Transaction ::change_by_selection ( doc . text ( ) , selection , | range | {
( range . from ( ) , range . to ( ) , None )
( range . from ( ) , range . to ( ) , None )
} ) ;
} ) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
match op {
match op {
Operation ::Delete = > {
Operation ::Delete = > {
@ -2176,7 +2191,7 @@ fn delete_selection_insert_mode(doc: &mut Document, view: &mut View, selection:
let transaction = Transaction ::change_by_selection ( doc . text ( ) , selection , | range | {
let transaction = Transaction ::change_by_selection ( doc . text ( ) , selection , | range | {
( range . from ( ) , range . to ( ) , None )
( range . from ( ) , range . to ( ) , None )
} ) ;
} ) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
}
}
fn delete_selection ( cx : & mut Context ) {
fn delete_selection ( cx : & mut Context ) {
@ -2272,7 +2287,7 @@ fn append_mode(cx: &mut Context) {
doc . text ( ) ,
doc . text ( ) ,
[ ( end , end , Some ( doc . line_ending . as_str ( ) . into ( ) ) ) ] . into_iter ( ) ,
[ ( end , end , Some ( doc . line_ending . as_str ( ) . into ( ) ) ) ] . into_iter ( ) ,
) ;
) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
}
}
let selection = doc . selection ( view . id ) . clone ( ) . transform ( | range | {
let selection = doc . selection ( view . id ) . clone ( ) . transform ( | range | {
@ -2311,7 +2326,7 @@ fn buffer_picker(cx: &mut Context) {
impl ui ::menu ::Item for BufferMeta {
impl ui ::menu ::Item for BufferMeta {
type Data = ( ) ;
type Data = ( ) ;
fn label ( & self , _data : & Self ::Data ) -> Spans {
fn format ( & self , _data : & Self ::Data ) -> Row {
let path = self
let path = self
. path
. path
. as_deref ( )
. as_deref ( )
@ -2380,7 +2395,7 @@ fn jumplist_picker(cx: &mut Context) {
impl ui ::menu ::Item for JumpMeta {
impl ui ::menu ::Item for JumpMeta {
type Data = ( ) ;
type Data = ( ) ;
fn label ( & self , _data : & Self ::Data ) -> Spans {
fn format ( & self , _data : & Self ::Data ) -> Row {
let path = self
let path = self
. path
. path
. as_deref ( )
. as_deref ( )
@ -2453,7 +2468,7 @@ fn jumplist_picker(cx: &mut Context) {
impl ui ::menu ::Item for MappableCommand {
impl ui ::menu ::Item for MappableCommand {
type Data = ReverseKeymap ;
type Data = ReverseKeymap ;
fn label ( & self , keymap : & Self ::Data ) -> Spans {
fn format ( & self , keymap : & Self ::Data ) -> Row {
let fmt_binding = | bindings : & Vec < Vec < KeyEvent > > | -> String {
let fmt_binding = | bindings : & Vec < Vec < KeyEvent > > | -> String {
bindings . iter ( ) . fold ( String ::new ( ) , | mut acc , bind | {
bindings . iter ( ) . fold ( String ::new ( ) , | mut acc , bind | {
if ! acc . is_empty ( ) {
if ! acc . is_empty ( ) {
@ -2582,7 +2597,7 @@ async fn make_format_callback(
if let Ok ( format ) = format {
if let Ok ( format ) = format {
if doc . version ( ) = = doc_version {
if doc . version ( ) = = doc_version {
apply_transaction ( & format , doc, view ) ;
doc. apply( & format , view. id ) ;
doc . append_changes_to_history ( view ) ;
doc . append_changes_to_history ( view ) ;
doc . detect_indent_and_line_ending ( ) ;
doc . detect_indent_and_line_ending ( ) ;
view . ensure_cursor_in_view ( doc , scrolloff ) ;
view . ensure_cursor_in_view ( doc , scrolloff ) ;
@ -2675,7 +2690,7 @@ fn open(cx: &mut Context, open: Open) {
transaction = transaction . with_selection ( Selection ::new ( ranges , selection . primary_index ( ) ) ) ;
transaction = transaction . with_selection ( Selection ::new ( ranges , selection . primary_index ( ) ) ) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
}
}
// o inserts a new line after each line with a selection
// o inserts a new line after each line with a selection
@ -3103,7 +3118,7 @@ pub mod insert {
let ( view , doc ) = current ! ( cx . editor ) ;
let ( view , doc ) = current ! ( cx . editor ) ;
if let Some ( t ) = transaction {
if let Some ( t ) = transaction {
apply_transaction ( & t , doc, view ) ;
doc. apply( & t , view. id ) ;
}
}
// TODO: need a post insert hook too for certain triggers (autocomplete, signature help, etc)
// TODO: need a post insert hook too for certain triggers (autocomplete, signature help, etc)
@ -3125,7 +3140,7 @@ pub mod insert {
& doc . selection ( view . id ) . clone ( ) . cursors ( doc . text ( ) . slice ( .. ) ) ,
& doc . selection ( view . id ) . clone ( ) . cursors ( doc . text ( ) . slice ( .. ) ) ,
indent ,
indent ,
) ;
) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
}
}
pub fn insert_newline ( cx : & mut Context ) {
pub fn insert_newline ( cx : & mut Context ) {
@ -3230,7 +3245,7 @@ pub mod insert {
transaction = transaction . with_selection ( Selection ::new ( ranges , selection . primary_index ( ) ) ) ;
transaction = transaction . with_selection ( Selection ::new ( ranges , selection . primary_index ( ) ) ) ;
let ( view , doc ) = current ! ( cx . editor ) ;
let ( view , doc ) = current ! ( cx . editor ) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
}
}
pub fn delete_char_backward ( cx : & mut Context ) {
pub fn delete_char_backward ( cx : & mut Context ) {
@ -3325,7 +3340,7 @@ pub mod insert {
}
}
} ) ;
} ) ;
let ( view , doc ) = current ! ( cx . editor ) ;
let ( view , doc ) = current ! ( cx . editor ) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
lsp ::signature_help_impl ( cx , SignatureHelpInvoked ::Automatic ) ;
lsp ::signature_help_impl ( cx , SignatureHelpInvoked ::Automatic ) ;
}
}
@ -3343,7 +3358,7 @@ pub mod insert {
None ,
None ,
)
)
} ) ;
} ) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
lsp ::signature_help_impl ( cx , SignatureHelpInvoked ::Automatic ) ;
lsp ::signature_help_impl ( cx , SignatureHelpInvoked ::Automatic ) ;
}
}
@ -3624,7 +3639,7 @@ fn paste_impl(
transaction = transaction . with_selection ( Selection ::new ( ranges , selection . primary_index ( ) ) ) ;
transaction = transaction . with_selection ( Selection ::new ( ranges , selection . primary_index ( ) ) ) ;
}
}
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
}
}
pub ( crate ) fn paste_bracketed_value ( cx : & mut Context , contents : String ) {
pub ( crate ) fn paste_bracketed_value ( cx : & mut Context , contents : String ) {
@ -3716,7 +3731,7 @@ fn replace_with_yanked(cx: &mut Context) {
}
}
} ) ;
} ) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
exit_select_mode ( cx ) ;
exit_select_mode ( cx ) ;
}
}
}
}
@ -3740,7 +3755,7 @@ fn replace_selections_with_clipboard_impl(
)
)
} ) ;
} ) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
doc . append_changes_to_history ( view ) ;
doc . append_changes_to_history ( view ) ;
}
}
Err ( e ) = > return Err ( e . context ( "Couldn't get system clipboard contents" ) ) ,
Err ( e ) = > return Err ( e . context ( "Couldn't get system clipboard contents" ) ) ,
@ -3812,7 +3827,7 @@ fn indent(cx: &mut Context) {
Some ( ( pos , pos , Some ( indent . clone ( ) ) ) )
Some ( ( pos , pos , Some ( indent . clone ( ) ) ) )
} ) ,
} ) ,
) ;
) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
}
}
fn unindent ( cx : & mut Context ) {
fn unindent ( cx : & mut Context ) {
@ -3851,7 +3866,7 @@ fn unindent(cx: &mut Context) {
let transaction = Transaction ::change ( doc . text ( ) , changes . into_iter ( ) ) ;
let transaction = Transaction ::change ( doc . text ( ) , changes . into_iter ( ) ) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
}
}
fn format_selections ( cx : & mut Context ) {
fn format_selections ( cx : & mut Context ) {
@ -3906,7 +3921,7 @@ fn format_selections(cx: &mut Context) {
language_server . offset_encoding ( ) ,
language_server . offset_encoding ( ) ,
) ;
) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
}
}
fn join_selections_impl ( cx : & mut Context , select_space : bool ) {
fn join_selections_impl ( cx : & mut Context , select_space : bool ) {
@ -3938,6 +3953,11 @@ fn join_selections_impl(cx: &mut Context, select_space: bool) {
}
}
}
}
// nothing to do, bail out early to avoid crashes later
if changes . is_empty ( ) {
return ;
}
changes . sort_unstable_by_key ( | ( from , _to , _text ) | * from ) ;
changes . sort_unstable_by_key ( | ( from , _to , _text ) | * from ) ;
changes . dedup ( ) ;
changes . dedup ( ) ;
@ -3960,7 +3980,7 @@ fn join_selections_impl(cx: &mut Context, select_space: bool) {
Transaction ::change ( doc . text ( ) , changes . into_iter ( ) )
Transaction ::change ( doc . text ( ) , changes . into_iter ( ) )
} ;
} ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
}
}
fn keep_or_remove_selections_impl ( cx : & mut Context , remove : bool ) {
fn keep_or_remove_selections_impl ( cx : & mut Context , remove : bool ) {
@ -4103,7 +4123,7 @@ fn toggle_comments(cx: &mut Context) {
. map ( | tc | tc . as_ref ( ) ) ;
. map ( | tc | tc . as_ref ( ) ) ;
let transaction = comment ::toggle_line_comments ( doc . text ( ) , doc . selection ( view . id ) , token ) ;
let transaction = comment ::toggle_line_comments ( doc . text ( ) , doc . selection ( view . id ) , token ) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
exit_select_mode ( cx ) ;
exit_select_mode ( cx ) ;
}
}
@ -4159,7 +4179,7 @@ fn rotate_selection_contents(cx: &mut Context, direction: Direction) {
. map ( | ( range , fragment ) | ( range . from ( ) , range . to ( ) , Some ( fragment ) ) ) ,
. map ( | ( range , fragment ) | ( range . from ( ) , range . to ( ) , Some ( fragment ) ) ) ,
) ;
) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
}
}
fn rotate_selection_contents_forward ( cx : & mut Context ) {
fn rotate_selection_contents_forward ( cx : & mut Context ) {
@ -4317,6 +4337,10 @@ fn rotate_view(cx: &mut Context) {
cx . editor . focus_next ( )
cx . editor . focus_next ( )
}
}
fn rotate_view_reverse ( cx : & mut Context ) {
cx . editor . focus_prev ( )
}
fn jump_view_right ( cx : & mut Context ) {
fn jump_view_right ( cx : & mut Context ) {
cx . editor . focus_direction ( tree ::Direction ::Right )
cx . editor . focus_direction ( tree ::Direction ::Right )
}
}
@ -4688,7 +4712,7 @@ fn surround_add(cx: &mut Context) {
let transaction = Transaction ::change ( doc . text ( ) , changes . into_iter ( ) )
let transaction = Transaction ::change ( doc . text ( ) , changes . into_iter ( ) )
. with_selection ( Selection ::new ( ranges , selection . primary_index ( ) ) ) ;
. with_selection ( Selection ::new ( ranges , selection . primary_index ( ) ) ) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
exit_select_mode ( cx ) ;
exit_select_mode ( cx ) ;
} )
} )
}
}
@ -4728,7 +4752,7 @@ fn surround_replace(cx: &mut Context) {
( pos , pos + 1 , Some ( t ) )
( pos , pos + 1 , Some ( t ) )
} ) ,
} ) ,
) ;
) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
exit_select_mode ( cx ) ;
exit_select_mode ( cx ) ;
} ) ;
} ) ;
} )
} )
@ -4756,7 +4780,7 @@ fn surround_delete(cx: &mut Context) {
let transaction =
let transaction =
Transaction ::change ( doc . text ( ) , change_pos . into_iter ( ) . map ( | p | ( p , p + 1 , None ) ) ) ;
Transaction ::change ( doc . text ( ) , change_pos . into_iter ( ) . map ( | p | ( p , p + 1 , None ) ) ) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
exit_select_mode ( cx ) ;
exit_select_mode ( cx ) ;
} )
} )
}
}
@ -4971,7 +4995,7 @@ fn shell(cx: &mut compositor::Context, cmd: &str, behavior: &ShellBehavior) {
if behavior ! = & ShellBehavior ::Ignore {
if behavior ! = & ShellBehavior ::Ignore {
let transaction = Transaction ::change ( doc . text ( ) , changes . into_iter ( ) )
let transaction = Transaction ::change ( doc . text ( ) , changes . into_iter ( ) )
. with_selection ( Selection ::new ( ranges , selection . primary_index ( ) ) ) ;
. with_selection ( Selection ::new ( ranges , selection . primary_index ( ) ) ) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
doc . append_changes_to_history ( view ) ;
doc . append_changes_to_history ( view ) ;
}
}
@ -5034,7 +5058,7 @@ fn add_newline_impl(cx: &mut Context, open: Open) {
} ) ;
} ) ;
let transaction = Transaction ::change ( text , changes ) ;
let transaction = Transaction ::change ( text , changes ) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
}
}
enum IncrementDirection {
enum IncrementDirection {
@ -5101,7 +5125,7 @@ fn increment_impl(cx: &mut Context, increment_direction: IncrementDirection) {
let new_selection = Selection ::new ( new_selection_ranges , selection . primary_index ( ) ) ;
let new_selection = Selection ::new ( new_selection_ranges , selection . primary_index ( ) ) ;
let transaction = Transaction ::change ( doc . text ( ) , changes . into_iter ( ) ) ;
let transaction = Transaction ::change ( doc . text ( ) , changes . into_iter ( ) ) ;
let transaction = transaction . with_selection ( new_selection ) ;
let transaction = transaction . with_selection ( new_selection ) ;
apply_transaction ( & transaction , doc, view ) ;
doc. apply( & transaction , view. id ) ;
}
}
}
}