@ -3,60 +3,95 @@ use std::sync::Arc;
use arc_swap ::ArcSwap ;
use arc_swap ::ArcSwap ;
use helix_core ::syntax ;
use helix_core ::syntax ;
use helix_view ::graphics ::{ Margin , Rect , Style } ;
use helix_view ::graphics ::{ Margin , Rect , Style } ;
use helix_view ::input ::Event ;
use tui ::buffer ::Buffer ;
use tui ::buffer ::Buffer ;
use tui ::layout ::Alignment ;
use tui ::text ::Text ;
use tui ::widgets ::{ BorderType , Paragraph , Widget , Wrap } ;
use tui ::widgets ::{ BorderType , Paragraph , Widget , Wrap } ;
use crate ::compositor ::{ Component , Compositor , Context };
use crate ::compositor ::{ Component , Compositor , Context , EventResult };
use crate ::alt ;
use crate ::ui ::Markdown ;
use crate ::ui ::Markdown ;
use super ::Popup ;
use super ::Popup ;
pub struct Signature Help {
pub struct Signature {
signature : String ,
pub signature : String ,
signature_doc : Option < String > ,
pub signature_doc : Option < String > ,
/// Part of signature text
/// Part of signature text
active_param_range : Option < ( usize , usize ) > ,
pub active_param_range : Option < ( usize , usize ) > ,
}
pub struct SignatureHelp {
language : String ,
language : String ,
config_loader : Arc < ArcSwap < syntax ::Loader > > ,
config_loader : Arc < ArcSwap < syntax ::Loader > > ,
active_signature : usize ,
signatures : Vec < Signature > ,
}
}
impl SignatureHelp {
impl SignatureHelp {
pub const ID : & ' static str = "signature-help" ;
pub const ID : & ' static str = "signature-help" ;
pub fn new (
pub fn new (
signature : String ,
language : String ,
language : String ,
config_loader : Arc < ArcSwap < syntax ::Loader > > ,
config_loader : Arc < ArcSwap < syntax ::Loader > > ,
active_signature : usize ,
signatures : Vec < Signature > ,
) -> Self {
) -> Self {
Self {
Self {
signature ,
signature_doc : None ,
active_param_range : None ,
language ,
language ,
config_loader ,
config_loader ,
active_signature ,
signatures ,
}
}
}
}
pub fn set_signature_doc ( & mut self , signature_doc : Option < String > ) {
pub fn active_signature ( & self ) -> usize {
self . signature_doc = signature_doc ;
self . active_signature
}
pub fn set_active_param_range ( & mut self , offset : Option < ( usize , usize ) > ) {
self . active_param_range = offset ;
}
}
pub fn visible_popup ( compositor : & mut Compositor ) -> Option < & mut Popup < Self > > {
pub fn visible_popup ( compositor : & mut Compositor ) -> Option < & mut Popup < Self > > {
compositor . find_id ::< Popup < Self > > ( Self ::ID )
compositor . find_id ::< Popup < Self > > ( Self ::ID )
}
}
fn signature_index ( & self ) -> String {
format! ( "({}/{})" , self . active_signature + 1 , self . signatures . len ( ) )
}
}
}
impl Component for SignatureHelp {
impl Component for SignatureHelp {
fn handle_event ( & mut self , event : & Event , _cx : & mut Context ) -> EventResult {
let Event ::Key ( event ) = event else {
return EventResult ::Ignored ( None ) ;
} ;
if self . signatures . len ( ) < = 1 {
return EventResult ::Ignored ( None ) ;
}
match event {
alt ! ( 'p' ) = > {
self . active_signature = self
. active_signature
. checked_sub ( 1 )
. unwrap_or ( self . signatures . len ( ) - 1 ) ;
EventResult ::Consumed ( None )
}
alt ! ( 'n' ) = > {
self . active_signature = ( self . active_signature + 1 ) % self . signatures . len ( ) ;
EventResult ::Consumed ( None )
}
_ = > EventResult ::Ignored ( None ) ,
}
}
fn render ( & mut self , area : Rect , surface : & mut Buffer , cx : & mut Context ) {
fn render ( & mut self , area : Rect , surface : & mut Buffer , cx : & mut Context ) {
let margin = Margin ::horizontal ( 1 ) ;
let margin = Margin ::horizontal ( 1 ) ;
let active_param_span = self . active_param_range . map ( | ( start , end ) | {
let signature = & self . signatures [ self . active_signature ] ;
let active_param_span = signature . active_param_range . map ( | ( start , end ) | {
vec! [ (
vec! [ (
cx . editor
cx . editor
. theme
. theme
@ -66,21 +101,29 @@ impl Component for SignatureHelp {
) ]
) ]
} ) ;
} ) ;
let sig = & self . signatures [ self . active_signature ] ;
let sig_text = crate ::ui ::markdown ::highlighted_code_block (
let sig_text = crate ::ui ::markdown ::highlighted_code_block (
& self . signature ,
sig . signature . as_str ( ) ,
& self . language ,
& self . language ,
Some ( & cx . editor . theme ) ,
Some ( & cx . editor . theme ) ,
Arc ::clone ( & self . config_loader ) ,
Arc ::clone ( & self . config_loader ) ,
active_param_span ,
active_param_span ,
) ;
) ;
if self . signatures . len ( ) > 1 {
let signature_index = self . signature_index ( ) ;
let text = Text ::from ( signature_index ) ;
let paragraph = Paragraph ::new ( & text ) . alignment ( Alignment ::Right ) ;
paragraph . render ( area . clip_top ( 1 ) . with_height ( 1 ) . clip_right ( 1 ) , surface ) ;
}
let ( _ , sig_text_height ) = crate ::ui ::text ::required_size ( & sig_text , area . width ) ;
let ( _ , sig_text_height ) = crate ::ui ::text ::required_size ( & sig_text , area . width ) ;
let sig_text_area = area . clip_top ( 1 ) . with_height ( sig_text_height ) ;
let sig_text_area = area . clip_top ( 1 ) . with_height ( sig_text_height ) ;
let sig_text_area = sig_text_area . inner ( & margin ) . intersection ( surface . area ) ;
let sig_text_area = sig_text_area . inner ( & margin ) . intersection ( surface . area ) ;
let sig_text_para = Paragraph ::new ( & sig_text ) . wrap ( Wrap { trim : false } ) ;
let sig_text_para = Paragraph ::new ( & sig_text ) . wrap ( Wrap { trim : false } ) ;
sig_text_para . render ( sig_text_area , surface ) ;
sig_text_para . render ( sig_text_area , surface ) ;
if self . signature_doc . is_none ( ) {
if sig . signature_doc . is_none ( ) {
return ;
return ;
}
}
@ -92,7 +135,7 @@ impl Component for SignatureHelp {
}
}
}
}
let sig_doc = match & self . signature_doc {
let sig_doc = match & sig . signature_doc {
None = > return ,
None = > return ,
Some ( doc ) = > Markdown ::new ( doc . clone ( ) , Arc ::clone ( & self . config_loader ) ) ,
Some ( doc ) = > Markdown ::new ( doc . clone ( ) , Arc ::clone ( & self . config_loader ) ) ,
} ;
} ;
@ -110,13 +153,15 @@ impl Component for SignatureHelp {
const PADDING : u16 = 2 ;
const PADDING : u16 = 2 ;
const SEPARATOR_HEIGHT : u16 = 1 ;
const SEPARATOR_HEIGHT : u16 = 1 ;
let sig = & self . signatures [ self . active_signature ] ;
if PADDING > = viewport . 1 | | PADDING > = viewport . 0 {
if PADDING > = viewport . 1 | | PADDING > = viewport . 0 {
return None ;
return None ;
}
}
let max_text_width = ( viewport . 0 - PADDING ) . min ( 120 ) ;
let max_text_width = ( viewport . 0 - PADDING ) . min ( 120 ) ;
let signature_text = crate ::ui ::markdown ::highlighted_code_block (
let signature_text = crate ::ui ::markdown ::highlighted_code_block (
& self . signature ,
sig . signature . as_str ( ) ,
& self . language ,
& self . language ,
None ,
None ,
Arc ::clone ( & self . config_loader ) ,
Arc ::clone ( & self . config_loader ) ,
@ -125,7 +170,7 @@ impl Component for SignatureHelp {
let ( sig_width , sig_height ) =
let ( sig_width , sig_height ) =
crate ::ui ::text ::required_size ( & signature_text , max_text_width ) ;
crate ::ui ::text ::required_size ( & signature_text , max_text_width ) ;
let ( width , height ) = match self . signature_doc {
let ( width , height ) = match sig . signature_doc {
Some ( ref doc ) = > {
Some ( ref doc ) = > {
let doc_md = Markdown ::new ( doc . clone ( ) , Arc ::clone ( & self . config_loader ) ) ;
let doc_md = Markdown ::new ( doc . clone ( ) , Arc ::clone ( & self . config_loader ) ) ;
let doc_text = doc_md . parse ( None ) ;
let doc_text = doc_md . parse ( None ) ;
@ -139,6 +184,12 @@ impl Component for SignatureHelp {
None = > ( sig_width , sig_height ) ,
None = > ( sig_width , sig_height ) ,
} ;
} ;
Some ( ( width + PADDING , height + PADDING ) )
let sig_index_width = if self . signatures . len ( ) > 1 {
self . signature_index ( ) . len ( ) + 1
} else {
0
} ;
Some ( ( width + PADDING + sig_index_width as u16 , height + PADDING ) )
}
}
}
}