diff options
author | Norbert Preining <norbert@preining.info> | 2024-03-17 03:01:42 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2024-03-17 03:01:42 +0000 |
commit | 55140d5421e1ad0024c9acbfa72bd06402c2aa9f (patch) | |
tree | b6c0d76888f025b58f1221d8dadbefb0264e9f6c /support | |
parent | 966f9ba332e49c29e961cb86e08f97d70eda51f6 (diff) |
CTAN sync 202403170301
Diffstat (limited to 'support')
53 files changed, 823 insertions, 261 deletions
diff --git a/support/latexindent/LatexIndent/BackUpFileProcedure.pm b/support/latexindent/LatexIndent/BackUpFileProcedure.pm index 7828c44be3..f88304fc6c 100644 --- a/support/latexindent/LatexIndent/BackUpFileProcedure.pm +++ b/support/latexindent/LatexIndent/BackUpFileProcedure.pm @@ -26,6 +26,10 @@ use Exporter qw/import/; use Encode qw/decode/; our @EXPORT_OK = qw/create_back_up_file check_if_different/; +use LatexIndent::UTF8CmdLineArgsFileOperation + qw/copy_with_encode exist_with_encode open_with_encode zero_with_encode read_yaml_with_encode/; +use utf8; + # copy main file to a backup in the case of the overwrite switch being active sub create_back_up_file { @@ -36,7 +40,7 @@ sub create_back_up_file { # if we want to overwrite the current file create a backup first $logger->info("*Backup procedure (-w flag active):"); - my $fileName = decode( "utf-8", ${$self}{fileName} ); + my $fileName = ${$self}{fileName}; # grab the file extension preferences my %fileExtensionPreference = %{ $mainSettings{fileExtensionPreference} }; @@ -49,7 +53,7 @@ sub create_back_up_file { my $backupFileNoExt = basename( ${$self}{fileName}, @fileExtensions ); # add the user's backup directory to the backup path - $backupFileNoExt = decode( "utf-8", "${$self}{cruftDirectory}/$backupFileNoExt" ); + $backupFileNoExt = "${$self}{cruftDirectory}/$backupFileNoExt"; # local variables, determined from the YAML settings my $onlyOneBackUp = $mainSettings{onlyOneBackUp}; @@ -74,7 +78,7 @@ sub create_back_up_file { # if the file already exists, increment the number until either # the file does not exist, or you reach the maximal number of backups - while ( -e ( $backupFile . $backupCounter ) and $backupCounter != ( $maxNumberOfBackUps - 1 ) ) { + while ( exist_with_encode( $backupFile . $backupCounter ) and $backupCounter != ( $maxNumberOfBackUps - 1 ) ) { $logger->info("$backupFile$backupCounter already exists, incrementing by 1 (see maxNumberOfBackUps)"); $backupCounter++; } @@ -83,7 +87,7 @@ sub create_back_up_file { # if the backup file already exists, output some information in the log file # and proceed to cycleThroughBackUps if the latter is set - if ( -e $backupFile ) { + if ( exist_with_encode($backupFile) ) { if ($onlyOneBackUp) { $logger->info("$backupFile will be overwritten (see onlyOneBackUp)"); } @@ -105,9 +109,9 @@ sub create_back_up_file { $newBackupFile = $backupFileNoExt . $backupExtension . ( $i - 1 ); # check that the oldBackupFile exists - if ( -e $oldBackupFile ) { + if ( exist_with_encode($oldBackupFile) ) { $logger->info("Copying $oldBackupFile to $newBackupFile..."); - if ( !( copy( $oldBackupFile, $newBackupFile ) ) ) { + if ( !( copy_with_encode( $oldBackupFile, $newBackupFile ) ) ) { $logger->fatal("*Could not write to backup file $newBackupFile. Please check permissions."); $logger->fatal("Exiting, no indentation done."); $self->output_logfile(); @@ -122,7 +126,7 @@ sub create_back_up_file { # output these lines to the log file $logger->info("Backing up $fileName to $backupFile..."); $logger->info("$fileName will be overwritten after indentation"); - if ( !( copy( $fileName, $backupFile ) ) ) { + if ( !( copy_with_encode( $fileName, $backupFile ) ) ) { $logger->fatal("*Could not write to backup file $backupFile. Please check permissions."); $logger->fatal("Exiting, no indentation done."); $self->output_logfile(); diff --git a/support/latexindent/LatexIndent/Document.pm b/support/latexindent/LatexIndent/Document.pm index 04c8e638dc..b6d2fa582a 100644 --- a/support/latexindent/LatexIndent/Document.pm +++ b/support/latexindent/LatexIndent/Document.pm @@ -19,7 +19,8 @@ use strict; use warnings; use Data::Dumper; use File::Basename; # to get the filename and directory path -use open ':std', ':encoding(UTF-8)'; + +#use open ':std', ':encoding(UTF-8)'; use Encode qw/decode/; # gain access to subroutines in the following modules @@ -73,6 +74,10 @@ use LatexIndent::Heading qw/find_heading construct_headings_levels $allHead use LatexIndent::FileContents qw/find_file_contents_environments_and_preamble/; use LatexIndent::Preamble; +use LatexIndent::UTF8CmdLineArgsFileOperation + qw/copy_with_encode exist_with_encode open_with_encode zero_with_encode read_yaml_with_encode/; +use utf8; + sub new { # Create new objects, with optional key/value pairs @@ -98,7 +103,7 @@ sub latexindent { # one-time operations $self->store_switches; - ${$self}{fileName} = decode( "utf-8", $fileNames[0] ); + ${$self}{fileName} = $fileNames[0]; $self->process_switches( \@fileNames ); $self->yaml_read_settings; @@ -231,19 +236,18 @@ sub output_indented_text { if ( ${$self}{overwrite} ) { # diacritics in file names (highlighted in https://github.com/cmhughes/latexindent.pl/pull/439) - ${$self}{fileName} = decode( "utf-8", ${$self}{fileName} ); + ${$self}{fileName} = ${$self}{fileName}; $logger->info("Overwriting file ${$self}{fileName}"); - open( OUTPUTFILE, ">", ${$self}{fileName} ); - print OUTPUTFILE ${$self}{body}; - close(OUTPUTFILE); + my $OUTPUTFILE = open_with_encode( '>:encoding(UTF-8)', ${$self}{fileName} ); + print $OUTPUTFILE ${$self}{body}; + close($OUTPUTFILE); } elsif ( $switches{outputToFile} ) { - $logger->info("Outputting to file ${$self}{outputToFile}"); - open( OUTPUTFILE, ">", ${$self}{outputToFile} ); - print OUTPUTFILE ${$self}{body}; - close(OUTPUTFILE); + my $OUTPUTFILE = open_with_encode( '>:encoding(UTF-8)', ${$self}{outputToFile} ); + print $OUTPUTFILE ${$self}{body}; + close($OUTPUTFILE); } else { $logger->info("Not outputting to file; see -w and -o switches for more options."); @@ -268,10 +272,10 @@ sub output_logfile { if ${ $mainSettings{logFilePreferences} }{showGitHubInfoFooter}; # open log file - my $logfileName = $switches{logFileName} || "indent.log"; - my $logfile; + my $logfileName = $switches{logFileName} || "indent.log"; my $logfilePossible = 1; - open( $logfile, ">", "${$self}{cruftDirectory}/$logfileName" ) or $logfilePossible = 0; + my $logfile = open_with_encode( '>:encoding(UTF-8)', "${$self}{cruftDirectory}/$logfileName" ) + or $logfilePossible = 0; if ($logfilePossible) { foreach my $line ( @{LatexIndent::Logger::logFileLines} ) { diff --git a/support/latexindent/LatexIndent/FileExtension.pm b/support/latexindent/LatexIndent/FileExtension.pm index bd909b2f60..64b5f0a37e 100644 --- a/support/latexindent/LatexIndent/FileExtension.pm +++ b/support/latexindent/LatexIndent/FileExtension.pm @@ -18,7 +18,8 @@ package LatexIndent::FileExtension; use strict; use warnings; use PerlIO::encoding; -use open ':std', ':encoding(UTF-8)'; + +#use open ':std', ':encoding(UTF-8)'; use File::Basename; # to get the filename and directory path use Exporter qw/import/; use Encode qw/decode/; @@ -27,6 +28,10 @@ use LatexIndent::Switches qw/%switches $is_check_switch_active/; use LatexIndent::LogFile qw/$logger/; our @EXPORT_OK = qw/file_extension_check/; +use LatexIndent::UTF8CmdLineArgsFileOperation + qw/copy_with_encode exist_with_encode open_with_encode zero_with_encode read_yaml_with_encode/; +use utf8; + sub file_extension_check { my $self = shift; @@ -59,7 +64,7 @@ sub file_extension_check { # loop through the known file extensions (see @fileExtensions) foreach (@fileExtensions) { - if ( -e $fileName . $_ ) { + if ( exist_with_encode( $fileName . $_ ) ) { $logger->info("$fileName$_ found!"); $fileName .= $_; $logger->info("Updated fileName to $fileName"); @@ -91,7 +96,7 @@ sub file_extension_check { } else { # if the file has a recognised extension, check that the file exists - unless ( -e $fileName ) { + unless ( exist_with_encode($fileName) ) { if ( defined ${$self}{multipleFiles} ) { $logger->warn("*I couldn't find $fileName, are you sure it exists?"); $logger->warn("moving on, no indentation done for ${$self}{fileName}."); @@ -120,7 +125,7 @@ sub file_extension_check { # note, related: # # git config --add core.quotePath false - ${$self}{outputToFile} = decode( "utf-8", $switches{outputToFile} ); + ${$self}{outputToFile} = $switches{outputToFile}; if ( $fileName eq "-" and $switches{outputToFile} =~ m/^\+/ ) { $logger->info("STDIN input mode active, -o switch is removing all + symbols"); @@ -130,7 +135,7 @@ sub file_extension_check { # the -o file name might begin with a + symbol if ( $switches{outputToFile} =~ m/^\+(.*)/ and $1 ne "+" ) { $logger->info("-o switch called with + symbol at the beginning: ${$self}{outputToFile}"); - ${$self}{outputToFile} = decode( "utf-8", ${$self}{baseName} . $1 ); + ${$self}{outputToFile} = ${$self}{baseName} . $1; $logger->info("output file is now: ${$self}{outputToFile}"); } @@ -143,9 +148,9 @@ sub file_extension_check { # if there is no extension, then add the extension from the file to be operated upon if ( !$ext ) { - $logger->info( - "-o switch called with file name without extension: " . decode( "utf-8", $switches{outputToFile} ) ); + $logger->info( "-o switch called with file name without extension: " . $switches{outputToFile} ); ${$self}{outputToFile} = $name . ( $name =~ m/\.\z/ ? q() : "." ) . $strippedFileExtension; + $logger->info( "Updated to ${$self}{outputToFile} as the file extension of the input file is $strippedFileExtension"); } @@ -160,7 +165,7 @@ sub file_extension_check { my $outputFileCounter = 0; my $fileName = $name . $outputFileCounter . "." . $strippedFileExtension; $logger->info("will search for existence and increment counter, starting with $fileName"); - while ( -e $fileName ) { + while ( exist_with_encode($fileName) ) { $logger->info("$fileName exists, incrementing counter"); $outputFileCounter++; $fileName = $name . $outputFileCounter . "." . $strippedFileExtension; @@ -174,7 +179,7 @@ sub file_extension_check { my @lines; if ( $fileName ne "-" ) { my $openFilePossible = 1; - open( MAINFILE, $fileName ) or ( $openFilePossible = 0 ); + my $MAINFILE = open_with_encode( '<:encoding(UTF-8)', $fileName ) or ( $openFilePossible = 0 ); if ( $openFilePossible == 0 ) { if ( defined ${$self}{multipleFiles} ) { $logger->warn("*$fileName exists, but could not open it"); @@ -188,8 +193,8 @@ sub file_extension_check { exit(4); } } - push( @lines, $_ ) while (<MAINFILE>); - close(MAINFILE); + push( @lines, $_ ) while (<$MAINFILE>); + close($MAINFILE); } else { push( @lines, $_ ) while (<>); diff --git a/support/latexindent/LatexIndent/GetYamlSettings.pm b/support/latexindent/LatexIndent/GetYamlSettings.pm index 7f3f507076..9e5ff7a853 100644 --- a/support/latexindent/LatexIndent/GetYamlSettings.pm +++ b/support/latexindent/LatexIndent/GetYamlSettings.pm @@ -34,6 +34,10 @@ our $defaultSettings; # master yaml settings is a hash, global to this module our %mainSettings; +use LatexIndent::UTF8CmdLineArgsFileOperation + qw/copy_with_encode exist_with_encode open_with_encode zero_with_encode read_yaml_with_encode/; +use utf8; + # previously found settings is a hash, global to this module our %previouslyFoundSettings; @@ -344,14 +348,15 @@ sub yaml_read_settings { } # diacritics in YAML names (highlighted in https://github.com/cmhughes/latexindent.pl/pull/439) - $_ = decode( "utf-8", $_ ); + #$_ = decode( "utf-8", $_ ); + $_ = $_; # check for existence and non-emptiness - if ( ( -e $_ ) and !( -z $_ ) ) { + if ( exist_with_encode($_) and !( zero_with_encode($_) ) ) { $logger->info("Adding $_ to YAML read paths"); push( @absPaths, "$_" ); } - elsif ( !( -e $_ ) ) { + elsif ( !( exist_with_encode($_) ) ) { if (( $_ =~ m/localSettings|latexindent/s and !( -e 'localSettings.yaml' ) and !( -e '.localSettings.yaml' ) @@ -373,9 +378,9 @@ sub yaml_read_settings { foreach my $settings (@absPaths) { # check that the settings file exists and that it isn't empty - if ( -e $settings and !( -z $settings ) ) { + if ( exist_with_encode($settings) and !( zero_with_encode($settings) ) ) { $logger->info("Reading USER settings from $settings"); - $userSettings = YAML::Tiny->read("$settings"); + $userSettings = read_yaml_with_encode("$settings"); # if we can read userSettings if ($userSettings) { @@ -513,7 +518,7 @@ sub yaml_read_settings { else { # otherwise keep going, but put a warning in the log file $logger->warn("*$homeDir/indentconfig.yaml"); - if ( -z $settings ) { + if ( zero_with_encode($settings) ) { $logger->info("specifies $settings but this file is EMPTY -- not reading from it"); } else { diff --git a/support/latexindent/LatexIndent/LogFile.pm b/support/latexindent/LatexIndent/LogFile.pm index b72655b686..7418f1024c 100644 --- a/support/latexindent/LatexIndent/LogFile.pm +++ b/support/latexindent/LatexIndent/LogFile.pm @@ -27,6 +27,12 @@ use Encode qw/decode/; our @EXPORT_OK = qw/process_switches $logger/; our $logger; +use utf8; +binmode( STDOUT, ":encoding(utf8)" ); + +use LatexIndent::UTF8CmdLineArgsFileOperation + qw/copy_with_encode exist_with_encode open_with_encode zero_with_encode read_yaml_with_encode isdir_with_encode mkdir_with_encode/; + sub process_switches { # -v switch is just to show the version number @@ -133,10 +139,10 @@ ENDQUOTE my $cruftDirectoryCreation = 0; # if cruft directory does not exist, create it - if ( !( -d ${$self}{cruftDirectory} ) ) { - eval { make_path( ${$self}{cruftDirectory} ) }; + if ( !( isdir_with_encode( ${$self}{cruftDirectory} ) ) ) { + eval { mkdir_with_encode( ${$self}{cruftDirectory} ) }; if ($@) { - $logger->fatal( "*Could not create cruft directory " . decode( "utf-8", ${$self}{cruftDirectory} ) ); + $logger->fatal( "*Could not create cruft directory " . ${$self}{cruftDirectory} ); $logger->fatal("Exiting, no indentation done."); $self->output_logfile(); exit(6); @@ -147,7 +153,7 @@ ENDQUOTE my $logfileName = ( $switches{cruftDirectory} ? ${$self}{cruftDirectory} . "/" : '' ) . ( $switches{logFileName} || "indent.log" ); - $logfileName = decode( "utf-8", $logfileName ); + $logfileName = $logfileName; # details of the script to log file $logger->info("*$FindBin::Script version $versionNumber, $versionDate, a script to indent .tex files"); @@ -204,6 +210,8 @@ ENDQUOTE $logger->info("-c|--cruft: cruft directory") if ( $switches{cruftDirectory} ); $logger->info("-r|--replacement: replacement mode") if ( $switches{replacement} ); $logger->info("-rr|--onlyreplacement: *only* replacement mode, no indentation") if ( $switches{onlyreplacement} ); + $logger->info("-rv|--replacementrespectverb replacement mode, respecting verbatim") + if ( $switches{replacementRespectVerb} ); $logger->info("-k|--check mode: will exit with 0 if document body unchanged, 1 if changed") if ( $switches{check} ); $logger->info("-kv|--check mode verbose: as in check mode, but outputs diff to screen") if ( $switches{checkverbose} ); @@ -253,7 +261,7 @@ ENDQUOTE } $logger->info("*Directory for backup files and $logfileName:"); - $logger->info( $switches{cruftDirectory} ? decode( "utf-8", ${$self}{cruftDirectory} ) : ${$self}{cruftDirectory} ); + $logger->info( $switches{cruftDirectory} ? ${$self}{cruftDirectory} : ${$self}{cruftDirectory} ); $logger->info("cruft directory creation: ${$self}{cruftDirectory}") if $cruftDirectoryCreation; # output location of modules diff --git a/support/latexindent/LatexIndent/UTF8CmdLineArgsFileOperation.pm b/support/latexindent/LatexIndent/UTF8CmdLineArgsFileOperation.pm new file mode 100644 index 0000000000..a2ba0b1d2f --- /dev/null +++ b/support/latexindent/LatexIndent/UTF8CmdLineArgsFileOperation.pm @@ -0,0 +1,209 @@ +package LatexIndent::UTF8CmdLineArgsFileOperation; + +use strict; +use warnings; +use feature qw( say state ); +use utf8; +use Config qw( %Config ); +use Encode qw( decode encode ); + +use Exporter qw/import/; +our @EXPORT_OK + = qw/commandlineargs_with_encode @new_args copy_with_encode exist_with_encode open_with_encode zero_with_encode read_yaml_with_encode isdir_with_encode mkdir_with_encode/; + +sub copy_with_encode { + use File::Copy; + my ( $source, $destination ) = @_; + + if ( $FindBin::Script eq 'latexindent.exe' ) { + require Win32::Unicode::File; + Win32::Unicode::File->import(qw(copyW)); + copyW( $source, $destination, 1 ); + } + else { + copy( $source, $destination ); + } +} + +sub exist_with_encode { + my ($filename) = @_; + + if ( $FindBin::Script eq 'latexindent.exe' ) { + require Win32::Unicode::File; + Win32::Unicode::File->import(qw(statW)); + return statW($filename); + } + else { + return -e $filename; + } +} + +sub zero_with_encode { + my ($filename) = @_; + + if ( $FindBin::Script eq 'latexindent.exe' ) { + require Win32::Unicode::File; + Win32::Unicode::File->import(qw(file_size)); + my $size = file_size($filename); + if ($size) { + return 0; + } + else { + return 1; + } + } + else { + return -z $filename; + } +} + +sub open_with_encode { + my $mode = shift; + my $filename = shift; + my $fh; + + if ( $FindBin::Script eq 'latexindent.exe' ) { + require Win32::Unicode::File; + Win32::Unicode::File->import; + $fh = Win32::Unicode::File->new; + open $fh, $mode, $filename or die "Can't open file: $!"; + return $fh; + } + else { + open( $fh, $mode, $filename ) or die "Can't open file: $!"; + return $fh; + } +} + +sub read_yaml_with_encode { + use YAML::Tiny; + my $filename = shift; + + my $fh = open_with_encode( '<:encoding(UTF-8)', $filename ) or die $!; + my $yaml_string = join( "", <$fh> ); + return YAML::Tiny->read_string($yaml_string); +} + +sub isdir_with_encode { + my $path = shift; + + if ( $FindBin::Script eq 'latexindent.exe' ) { + require Win32::Unicode::File; + Win32::Unicode::File->import(qw(file_type)); + + return file_type( 'd', $path ); + } + else { + return -d $path; + } +} + +sub mkdir_with_encode { + my $path = shift; + + if ( $FindBin::Script eq 'latexindent.exe' ) { + require Win32::Unicode::Dir; + Win32::Unicode::Dir->import(qw(mkdirW)); + + mkdirW($path) or die "Cannot create directory $path: $!"; + } + else { + require File::Path; + File::Path->import(qw(make_path)); + + my $created = make_path($path); + die "Cannot create directory $path" unless $created; + } +} + +#https://stackoverflow.com/a/63868721 +#https://stackoverflow.com/a/44489228 +sub commandlineargs_with_encode { + if ( $FindBin::Script eq 'latexindent.exe' ) { + require Win32::API; + import Win32::API qw( ReadMemory ); + + #use open ':std', ':encoding('.do { require Win32; "cp".Win32::GetConsoleOutputCP() }.')'; + + use constant ptr_size => $Config{ptrsize}; + + use constant ptr_pack_format => ptr_size == 8 ? 'Q' + : ptr_size == 4 ? 'L' + : die("Unrecognized ptrsize\n"); + + use constant ptr_win32api_type => ptr_size == 8 ? 'Q' + : ptr_size == 4 ? 'N' + : die("Unrecognized ptrsize\n"); + + sub lstrlenw { + my ($ptr) = @_; + + state $lstrlenw = Win32::API->new( 'kernel32', 'lstrlenW', ptr_win32api_type, 'i' ) + or die($^E); + + return $lstrlenw->Call($ptr); + } + + sub decode_lpcwstr { + my ($ptr) = @_; + return undef if !$ptr; + + my $num_chars = lstrlenw($ptr) + or return ''; + + return decode( 'UTF-16le', ReadMemory( $ptr, $num_chars * 2 ) ); + } + + # Returns true on success. Returns false and sets $^E on error. + sub localfree { + my ($ptr) = @_; + + state $localfree = Win32::API->new( 'kernel32', 'LocalFree', ptr_win32api_type, ptr_win32api_type ) + or die($^E); + + return $localfree->Call($ptr) == 0; + } + + sub getcommandline { + state $getcommandline = Win32::API->new( 'kernel32', 'GetCommandLineW', '', ptr_win32api_type ) + or die($^E); + + return decode_lpcwstr( $getcommandline->Call() ); + } + + # Returns a reference to an array on success. Returns undef and sets $^E on error. + sub commandlinetoargv { + my ($cmd_line) = @_; + + state $commandlinetoargv = Win32::API->new( 'shell32', 'CommandLineToArgvW', 'PP', ptr_win32api_type ) + or die($^E); + + my $cmd_line_encoded = encode( 'UTF-16le', $cmd_line . "\0" ); + my $num_args_buf = pack( 'i', 0 ); # Allocate space for an "int". + + my $arg_ptrs_ptr = $commandlinetoargv->Call( $cmd_line_encoded, $num_args_buf ) + or return undef; + + my $num_args = unpack( 'i', $num_args_buf ); + my @args = map { decode_lpcwstr($_) } unpack ptr_pack_format . '*', + ReadMemory( $arg_ptrs_ptr, ptr_size * $num_args ); + + localfree($arg_ptrs_ptr); + return \@args; + } + + my $cmd_line = getcommandline(); + our @new_args = $cmd_line; + $cmd_line =~ s/(^(.*?)\.pl\"? )//g; + $cmd_line =~ s/(^(.*?)\.exe\"? )//g; + my $args = commandlinetoargv($cmd_line) or die("CommandLineToArgv: $^E\n"); + @ARGV = @{$args}; + } + else { + my $encodingObject = "utf-8"; + @ARGV = map { decode( $encodingObject, $_ ) } @ARGV; + our @new_args = @ARGV; + } +} + +1; diff --git a/support/latexindent/LatexIndent/Version.pm b/support/latexindent/LatexIndent/Version.pm index f56a438ec0..5da34c49b7 100644 --- a/support/latexindent/LatexIndent/Version.pm +++ b/support/latexindent/LatexIndent/Version.pm @@ -20,6 +20,6 @@ use warnings; use Exporter qw/import/; our @EXPORT_OK = qw/$versionNumber $versionDate/; -our $versionNumber = '3.23.6'; -our $versionDate = '2024-01-17'; +our $versionNumber = '3.23.7'; +our $versionDate = '2024-03-16'; 1 diff --git a/support/latexindent/README b/support/latexindent/README index 9a21dd77ce..c1336ed578 100644 --- a/support/latexindent/README +++ b/support/latexindent/README @@ -1,5 +1,5 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - latexindent.pl, version 3.23.6, 2024-01-17 + latexindent.pl, version 3.23.7, 2024-03-16 PERL script to indent code within environments, and align delimited environments in .tex files. diff --git a/support/latexindent/bin/linux/latexindent b/support/latexindent/bin/linux/latexindent Binary files differindex 831e122a92..1932df3381 100644 --- a/support/latexindent/bin/linux/latexindent +++ b/support/latexindent/bin/linux/latexindent diff --git a/support/latexindent/bin/macos/latexindent b/support/latexindent/bin/macos/latexindent Binary files differindex ad7ab51add..150f294502 100644 --- a/support/latexindent/bin/macos/latexindent +++ b/support/latexindent/bin/macos/latexindent diff --git a/support/latexindent/defaultSettings.yaml b/support/latexindent/defaultSettings.yaml index a00474e143..221bdb6b5d 100644 --- a/support/latexindent/defaultSettings.yaml +++ b/support/latexindent/defaultSettings.yaml @@ -1,5 +1,5 @@ # -# latexindent.pl, version 3.23.6, 2024-01-17 +# latexindent.pl, version 3.23.7, 2024-03-16 # # defaultSettings.yaml, the default settings for latexindent.pl # diff --git a/support/latexindent/documentation/latexindent-yaml-schema.json b/support/latexindent/documentation/latexindent-yaml-schema.json index 0bb03ddc43..9d6102987c 100644 --- a/support/latexindent/documentation/latexindent-yaml-schema.json +++ b/support/latexindent/documentation/latexindent-yaml-schema.json @@ -2,7 +2,7 @@ "$schema": "http://json-schema.org/schema", "$id": "latexindent-yaml-schema.json", "title": "latexindent.pl YAML schema", - "description": "latexindent.pl YAML schema helper, V3.23.6 2024-01-17", + "description": "latexindent.pl YAML schema helper, V3.23.7 2024-03-16", "type": "object", "properties": { "fileExtensionPreference": { diff --git a/support/latexindent/documentation/latexindent.pdf b/support/latexindent/documentation/latexindent.pdf Binary files differindex fe0fa82176..4029dee3cd 100644 --- a/support/latexindent/documentation/latexindent.pdf +++ b/support/latexindent/documentation/latexindent.pdf diff --git a/support/latexindent/latexindent.pl b/support/latexindent/latexindent.pl index e5c034dd77..dbb083cc48 100755 --- a/support/latexindent/latexindent.pl +++ b/support/latexindent/latexindent.pl @@ -1,6 +1,6 @@ #!/usr/bin/env perl # -# latexindent.pl, version 3.23.6, 2024-01-17 +# latexindent.pl, version 3.23.7, 2024-03-16 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -27,6 +27,16 @@ use Getopt::Long; # to get the switches/options/flags use lib $FindBin::RealBin; use LatexIndent::Document; +use utf8; +use Encode qw/ encode decode find_encoding /; + +use LatexIndent::LogFile qw/$logger/; +use LatexIndent::UTF8CmdLineArgsFileOperation + qw/commandlineargs_with_encode @new_args/; + +commandlineargs_with_encode(); +my $commandlineargs = join( ", ", @ARGV ); + # get the options my %switches = ( readLocalSettings => 0 ); @@ -56,6 +66,34 @@ GetOptions( "GCString" => \$switches{GCString}, ); +$logger = LatexIndent::Logger->new(); +our $consoleoutcp; +if ( $FindBin::Script eq 'latexindent.exe' ) { + require Win32; + import Win32; + + my $encoding_sys = Win32::GetACP() + ; #https://stackoverflow.com/a/63868721HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage + $consoleoutcp = Win32::GetConsoleOutputCP(); + Win32::SetConsoleOutputCP(65001); + + $logger->info("*ANSI Code Page: $encoding_sys"); + if ( $switches{screenlog} ) { + print "INFO: ANSI Code Page: $encoding_sys\n" + ; #The values of ACP in the registry + print "INFO: Current console output code page: $consoleoutcp \n"; + print "INFO: Change the current console output code page to 65001\n"; + } +} + +if ( $switches{screenlog} ) { + $logger->info("*Command line:"); + $logger->info("@new_args"); + $logger->info( "Command line arguments:\n" . $commandlineargs ); + print "INFO: Command line:\n @new_args\n"; + print " Command line arguments:\n " . $commandlineargs . "\n\n"; +} + # conditionally load the GCString module eval "use Unicode::GCString" if $switches{GCString}; @@ -86,4 +124,12 @@ my $document = bless( "LatexIndent::Document" ); $document->latexindent( \@ARGV ); + +if ( $FindBin::Script eq 'latexindent.exe' ) { + Win32::SetConsoleOutputCP($consoleoutcp); + if ( $switches{screenlog} ) { + print + "\n\nINFO: Restore the console output code page: $consoleoutcp\n"; + } +} exit(0); diff --git a/support/texlab/CHANGELOG.md b/support/texlab/CHANGELOG.md index 928eb0c10b..fdf40bd102 100644 --- a/support/texlab/CHANGELOG.md +++ b/support/texlab/CHANGELOG.md @@ -5,6 +5,34 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [5.13.1] - 2024-03-16 + +### Fixed + +- Fix clearing stale diagnostics reported by the server ([#1042](https://github.com/latex-lsp/texlab/issues/1042)) +- Speed up reading bibliographies with many string definitions ([#1039](https://github.com/latex-lsp/texlab/pull/1039)) + +## [5.13.0] - 2024-03-10 + +### Added + +- Add experimental `texlab.experimental.labelReferenceCommands` setting to customize the list of `\ref`-like commands + ([#1032](https://github.com/latex-lsp/texlab/issues/1032)) + +### Fixed + +- Don't report diagnostics for files that are part of the TeX distro ([#1028](https://github.com/latex-lsp/texlab/issues/1028)) + +## [5.12.4] - 2024-02-22 + +### Fixed + +- When `workspace/didChangeConfiguration` contains the configuration of multiple LSP servers, `texlab` will try + to extract the `texlab` configuration instead of falling back to the default settings + ([#1003](https://github.com/latex-lsp/texlab/issues/1003)) +- Keep filtering completion lists server-side if prefix matcher is set ([#1003](https://github.com/latex-lsp/texlab/issues/1003)) +- Allow brackets and parentheses in label names and similar constructs ([#1016](https://github.com/latex-lsp/texlab/issues/1016)) + ## [5.12.3] - 2024-01-27 ### Fixed diff --git a/support/texlab/Cargo.lock b/support/texlab/Cargo.lock index 64669f9f36..143c0137d7 100644 --- a/support/texlab/Cargo.lock +++ b/support/texlab/Cargo.lock @@ -25,9 +25,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.4" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" dependencies = [ "anstyle", "anstyle-parse", @@ -58,7 +58,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -68,7 +68,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -150,9 +150,9 @@ checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "bstr" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c" +checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" dependencies = [ "memchr", "regex-automata", @@ -172,15 +172,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] - -[[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -226,6 +217,7 @@ dependencies = [ name = "citeproc" version = "0.0.0" dependencies = [ + "base-db", "bibtex-utils", "expect-test", "isocountry", @@ -241,9 +233,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.10" +version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fffed7514f420abec6d183b1d3acfd9099c79c3a10a06ade4f8203f1411272" +checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" dependencies = [ "clap_builder", "clap_derive", @@ -251,9 +243,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.9" +version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63361bae7eef3771745f02d8d892bec2fee5f6e34af316ba556e7f97a7069ff1" +checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" dependencies = [ "anstream", "anstyle", @@ -481,7 +473,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -524,23 +516,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] [[package]] @@ -555,9 +536,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fern" @@ -574,7 +555,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6584280525fb2059cba3db2c04abf947a1a29a45ddae89f3870f8281704fafc9" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -586,7 +567,7 @@ dependencies = [ "cfg-if", "libc", "redox_syscall 0.3.5", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -770,7 +751,7 @@ checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -850,9 +831,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "line-index" @@ -873,9 +854,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.11" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lock_api" @@ -889,9 +870,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "logos" @@ -939,9 +920,9 @@ dependencies = [ [[package]] name = "lsp-types" -version = "0.94.1" +version = "0.95.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66bfd44a06ae10647fe3f8214762e9369fd4248df1350924b4ef9e770a85ea1" +checksum = "158c1911354ef73e8fe42da6b10c0484cb65c7f1007f28022e847706c1ab6984" dependencies = [ "bitflags 1.3.2", "serde", @@ -952,9 +933,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.3" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "memoffset" @@ -976,21 +957,21 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "multimap" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1a5d38b9b352dbd913288736af36af41c48d61b1a8cd34bcecd727561b7d511" +checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" dependencies = [ "serde", ] @@ -1011,7 +992,7 @@ dependencies = [ "log", "mio", "walkdir", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1085,7 +1066,7 @@ dependencies = [ "libc", "redox_syscall 0.3.5", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -1209,9 +1190,9 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" [[package]] name = "rayon" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" dependencies = [ "either", "rayon-core", @@ -1219,9 +1200,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -1246,15 +1227,6 @@ dependencies = [ ] [[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] name = "redox_users" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1342,15 +1314,15 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.38.21" +version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ "bitflags 2.4.0", "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -1396,9 +1368,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -1417,9 +1389,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" +checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" dependencies = [ "proc-macro2", "quote", @@ -1491,15 +1463,14 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.8.1" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.4.1", "rustix", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -1515,7 +1486,7 @@ dependencies = [ [[package]] name = "texlab" -version = "5.12.3" +version = "5.13.1" dependencies = [ "anyhow", "base-db", @@ -1570,18 +1541,18 @@ checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233" [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", @@ -1817,7 +1788,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.4", ] [[package]] @@ -1826,13 +1806,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] @@ -1842,37 +1837,79 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" diff --git a/support/texlab/crates/base-db/Cargo.toml b/support/texlab/crates/base-db/Cargo.toml index 0aceff8e5f..010c83d0e4 100644 --- a/support/texlab/crates/base-db/Cargo.toml +++ b/support/texlab/crates/base-db/Cargo.toml @@ -12,7 +12,7 @@ dirs = "5.0.1" distro = { path = "../distro" } itertools = "0.12.0" line-index = { path = "../line-index" } -log = "0.4.20" +log = "0.4.21" notify = "6.0.1" once_cell = "1.19.0" parser = { path = "../parser" } diff --git a/support/texlab/crates/base-db/src/document.rs b/support/texlab/crates/base-db/src/document.rs index 9f45876d7e..25607a1bf5 100644 --- a/support/texlab/crates/base-db/src/document.rs +++ b/support/texlab/crates/base-db/src/document.rs @@ -12,6 +12,7 @@ use crate::{semantics, Config}; pub enum Owner { Client, Server, + Distro, } #[derive(Debug)] diff --git a/support/texlab/crates/base-db/src/semantics/bib.rs b/support/texlab/crates/base-db/src/semantics/bib.rs index 14fa98fb6e..1a03fbb2c2 100644 --- a/support/texlab/crates/base-db/src/semantics/bib.rs +++ b/support/texlab/crates/base-db/src/semantics/bib.rs @@ -2,6 +2,7 @@ use bibtex_utils::field::text::TextFieldData; use itertools::Itertools; use rowan::{ast::AstNode, TextRange}; use syntax::bibtex::{self, HasName, HasType, HasValue}; +use rustc_hash::FxHashMap; use crate::data::{BibtexEntryType, BibtexEntryTypeCategory}; @@ -11,6 +12,8 @@ use super::Span; pub struct Semantics { pub entries: Vec<Entry>, pub strings: Vec<StringDef>, + /// Map from string definition keys to their expanded values. + pub expanded_defs: FxHashMap<String, String>, } impl Semantics { @@ -32,7 +35,7 @@ impl Semantics { let field_values = entry .fields() - .filter_map(|field| Some(TextFieldData::parse(&field.value()?)?.text)); + .filter_map(|field| Some(TextFieldData::parse(&field.value()?, &self.expanded_defs)?.text)); let keywords = [name.text().into(), type_token.text().into()] .into_iter() @@ -60,6 +63,11 @@ impl Semantics { }, full_range: string.syntax().text_range(), }); + if let Some(value) = string.value() { + if let Some(data) = TextFieldData::parse(&value, &self.expanded_defs) { + self.expanded_defs.insert(name.text().into(), data.text); + } + } } } } diff --git a/support/texlab/crates/base-db/src/workspace.rs b/support/texlab/crates/base-db/src/workspace.rs index 330ed5a493..0fe347f1b3 100644 --- a/support/texlab/crates/base-db/src/workspace.rs +++ b/support/texlab/crates/base-db/src/workspace.rs @@ -67,7 +67,7 @@ impl Workspace { })); } - pub fn load(&mut self, path: &Path, language: Language, owner: Owner) -> std::io::Result<()> { + pub fn load(&mut self, path: &Path, language: Language) -> std::io::Result<()> { log::debug!("Loading document {} from disk...", path.display()); let uri = Url::from_file_path(path).unwrap(); let data = std::fs::read(path)?; @@ -76,6 +76,12 @@ impl Workspace { Cow::Owned(text) => text, }; + let owner = if self.distro.file_name_db.contains(&path) { + Owner::Distro + } else { + Owner::Server + }; + if let Some(document) = self.lookup_path(path) { if document.text == text { return Ok(()); @@ -329,7 +335,7 @@ impl Workspace { } if self.lookup_path(&file).is_none() && file.exists() { - changed |= self.load(&file, lang, Owner::Server).is_ok(); + changed |= self.load(&file, lang).is_ok(); checked_paths.insert(file); } } @@ -350,8 +356,9 @@ impl Workspace { let mut changed = false; for file in files { let language = Language::from_path(&file).unwrap_or(Language::Tex); + if self.lookup_path(&file).is_none() && file.exists() { - changed |= self.load(&file, language, Owner::Server).is_ok(); + changed |= self.load(&file, language).is_ok(); checked_paths.insert(file); } } diff --git a/support/texlab/crates/bibtex-utils/src/field.rs b/support/texlab/crates/bibtex-utils/src/field.rs index d9f3adacab..71bd25f6d0 100644 --- a/support/texlab/crates/bibtex-utils/src/field.rs +++ b/support/texlab/crates/bibtex-utils/src/field.rs @@ -1,4 +1,9 @@ +use rustc_hash::FxHashMap; + pub mod author; pub mod date; pub mod number; pub mod text; + +/// A cache used to accelerate related field parses. +pub type FieldParseCache = FxHashMap<String, String>;
\ No newline at end of file diff --git a/support/texlab/crates/bibtex-utils/src/field/author.rs b/support/texlab/crates/bibtex-utils/src/field/author.rs index d8576cbaa4..4be999efbd 100644 --- a/support/texlab/crates/bibtex-utils/src/field/author.rs +++ b/support/texlab/crates/bibtex-utils/src/field/author.rs @@ -4,7 +4,7 @@ use human_name::Name; use itertools::Itertools; use syntax::bibtex::Value; -use super::text::TextFieldData; +use super::{text::TextFieldData, FieldParseCache}; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] pub enum AuthorField { @@ -58,8 +58,8 @@ impl fmt::Display for AuthorFieldData { } impl AuthorFieldData { - pub fn parse(value: &Value) -> Option<Self> { - let TextFieldData { text } = TextFieldData::parse(value)?; + pub fn parse(value: &Value, cache: &FieldParseCache) -> Option<Self> { + let TextFieldData { text } = TextFieldData::parse(value, cache)?; let mut authors = Vec::new(); let mut words = Vec::new(); for word in text.split_whitespace() { diff --git a/support/texlab/crates/bibtex-utils/src/field/date.rs b/support/texlab/crates/bibtex-utils/src/field/date.rs index 8e2c0b7d72..4e3dfd19d9 100644 --- a/support/texlab/crates/bibtex-utils/src/field/date.rs +++ b/support/texlab/crates/bibtex-utils/src/field/date.rs @@ -3,7 +3,7 @@ use std::{fmt, ops::Add, str::FromStr}; use chrono::{Datelike, Month, NaiveDate}; use syntax::bibtex::Value; -use super::text::TextFieldData; +use super::{text::TextFieldData, FieldParseCache}; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] pub enum DateField { @@ -73,8 +73,8 @@ impl fmt::Display for DateFieldData { } impl DateFieldData { - pub fn parse(value: &Value) -> Option<Self> { - let TextFieldData { text } = TextFieldData::parse(value)?; + pub fn parse(value: &Value, cache: &FieldParseCache) -> Option<Self> { + let TextFieldData { text } = TextFieldData::parse(value, cache)?; NaiveDate::from_str(&text) .ok() .map(Self::Date) diff --git a/support/texlab/crates/bibtex-utils/src/field/number.rs b/support/texlab/crates/bibtex-utils/src/field/number.rs index 227f3d5b75..34240bcfb3 100644 --- a/support/texlab/crates/bibtex-utils/src/field/number.rs +++ b/support/texlab/crates/bibtex-utils/src/field/number.rs @@ -2,7 +2,7 @@ use std::fmt; use syntax::bibtex::Value; -use super::text::TextFieldData; +use super::{text::TextFieldData, FieldParseCache}; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] pub enum NumberField { @@ -48,8 +48,8 @@ impl fmt::Display for NumberFieldData { } impl NumberFieldData { - pub fn parse(value: &Value) -> Option<Self> { - let TextFieldData { text } = TextFieldData::parse(value)?; + pub fn parse(value: &Value, cache: &FieldParseCache) -> Option<Self> { + let TextFieldData { text } = TextFieldData::parse(value, cache)?; text.split_once("--") .or_else(|| text.split_once('-')) .and_then(|(a, b)| Some((a.parse().ok()?, b.parse().ok()?))) diff --git a/support/texlab/crates/bibtex-utils/src/field/text.rs b/support/texlab/crates/bibtex-utils/src/field/text.rs index 9689264779..b3eabaff0e 100644 --- a/support/texlab/crates/bibtex-utils/src/field/text.rs +++ b/support/texlab/crates/bibtex-utils/src/field/text.rs @@ -1,11 +1,12 @@ use rowan::{ast::AstNode, NodeOrToken}; -use rustc_hash::FxHashSet; use syntax::bibtex::{ - Accent, Command, CurlyGroup, HasAccentName, HasCommandName, HasName, HasValue, HasWord, Join, - Literal, QuoteGroup, Root, SyntaxKind::*, SyntaxToken, Value, + Accent, Command, CurlyGroup, HasAccentName, HasCommandName, HasName, HasWord, Join, + Literal, QuoteGroup, SyntaxKind::*, SyntaxToken, Value, }; +use super::FieldParseCache; + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] pub enum TextField { Abstract, @@ -118,20 +119,28 @@ pub struct TextFieldData { } impl TextFieldData { - pub fn parse(value: &Value) -> Option<Self> { - let mut builder = TextFieldDataBuilder::default(); + pub fn parse(value: &Value, cache: &FieldParseCache) -> Option<Self> { + let mut builder = TextFieldDataBuilder::new(cache); builder.visit_value(value)?; Some(builder.data) } } -#[derive(Default)] -struct TextFieldDataBuilder { +struct TextFieldDataBuilder<'a> { data: TextFieldData, - string_stack: FxHashSet<String>, + cache: &'a FieldParseCache, +} + +impl<'a> TextFieldDataBuilder<'a> { + fn new(cache: &'a FieldParseCache) -> Self { + TextFieldDataBuilder { + data: Default::default(), + cache, + } + } } -impl TextFieldDataBuilder { +impl<'a> TextFieldDataBuilder<'a> { fn visit_value(&mut self, value: &Value) -> Option<()> { match value { Value::Literal(lit) => { @@ -170,24 +179,9 @@ impl TextFieldDataBuilder { } fn visit_string_reference(&mut self, name: &SyntaxToken) -> Option<()> { - let root = Root::cast(name.parent_ancestors().last()?)?; let name = name.text(); - - let value = root - .strings() - .filter(|string| { - string - .name_token() - .map_or(false, |token| token.text() == name) - }) - .find_map(|string| string.value())?; - - if !self.string_stack.insert(name.to_string()) { - return None; - } - - let _ = self.visit_value(&value); - self.string_stack.remove(name); + let value = self.cache.get(name)?; + self.data.text.push_str(value); Some(()) } diff --git a/support/texlab/crates/citeproc/Cargo.toml b/support/texlab/crates/citeproc/Cargo.toml index c87b2d17c3..9d356b3778 100644 --- a/support/texlab/crates/citeproc/Cargo.toml +++ b/support/texlab/crates/citeproc/Cargo.toml @@ -8,6 +8,7 @@ rust-version.workspace = true [dependencies] bibtex-utils = { path = "../bibtex-utils" } +base-db = { path = "../base-db" } isocountry = "0.3.2" itertools = "0.12.0" rowan = "0.15.15" diff --git a/support/texlab/crates/citeproc/src/driver.rs b/support/texlab/crates/citeproc/src/driver.rs index 778e2539b5..cee6bb097e 100644 --- a/support/texlab/crates/citeproc/src/driver.rs +++ b/support/texlab/crates/citeproc/src/driver.rs @@ -1,3 +1,4 @@ +use base_db::semantics::bib::Semantics; use bibtex_utils::field::{ author::AuthorField, date::DateField, @@ -21,8 +22,8 @@ pub struct Driver { } impl Driver { - pub fn process(&mut self, entry: &bibtex::Entry) { - let entry = EntryData::from(entry); + pub fn process(&mut self, entry: &bibtex::Entry, semantics: &Semantics) { + let entry = EntryData::from_entry(entry, semantics); match entry.kind { EntryKind::Article | EntryKind::DataSet diff --git a/support/texlab/crates/citeproc/src/entry.rs b/support/texlab/crates/citeproc/src/entry.rs index 243908da95..f544858efc 100644 --- a/support/texlab/crates/citeproc/src/entry.rs +++ b/support/texlab/crates/citeproc/src/entry.rs @@ -3,7 +3,9 @@ use bibtex_utils::field::{ date::{DateField, DateFieldData}, number::{NumberField, NumberFieldData}, text::{TextField, TextFieldData}, + FieldParseCache, }; +use base_db::semantics::bib::Semantics; use rustc_hash::FxHashMap; use syntax::bibtex::{Entry, Field, HasName, HasType, HasValue, Value}; @@ -103,8 +105,8 @@ pub struct EntryData { pub number: FxHashMap<NumberField, NumberFieldData>, } -impl From<&Entry> for EntryData { - fn from(entry: &Entry) -> Self { +impl EntryData { + pub fn from_entry(entry: &Entry, semantics: &Semantics) -> Self { let mut data = EntryData { kind: entry.type_token().map_or(EntryKind::Unknown, |token| { EntryKind::parse(&token.text()[1..]) @@ -113,7 +115,7 @@ impl From<&Entry> for EntryData { }; for field in entry.fields() { - let _ = data.parse_field(&field); + let _ = data.parse_field(&field, &semantics.expanded_defs); } data @@ -121,40 +123,40 @@ impl From<&Entry> for EntryData { } impl EntryData { - fn parse_field(&mut self, field: &Field) -> Option<()> { + fn parse_field(&mut self, field: &Field, expanded_defs: &FieldParseCache) -> Option<()> { let name = field.name_token()?; let name = name.text(); let value = field.value()?; - self.parse_author_field(name, &value) - .or_else(|| self.parse_date_field(name, &value)) - .or_else(|| self.parse_number_field(name, &value)) - .or_else(|| self.parse_text_field(name, &value)) + self.parse_author_field(name, &value, expanded_defs) + .or_else(|| self.parse_date_field(name, &value, expanded_defs)) + .or_else(|| self.parse_number_field(name, &value, expanded_defs)) + .or_else(|| self.parse_text_field(name, &value, expanded_defs)) } - fn parse_author_field(&mut self, name: &str, value: &Value) -> Option<()> { + fn parse_author_field(&mut self, name: &str, value: &Value, expanded_defs: &FieldParseCache) -> Option<()> { let name = AuthorField::parse(name)?; - let data = AuthorFieldData::parse(value)?; + let data = AuthorFieldData::parse(value, expanded_defs)?; self.author.insert(name, data); Some(()) } - fn parse_date_field(&mut self, name: &str, value: &Value) -> Option<()> { + fn parse_date_field(&mut self, name: &str, value: &Value, expanded_defs: &FieldParseCache) -> Option<()> { let name = DateField::parse(name)?; - let data = DateFieldData::parse(value)?; + let data = DateFieldData::parse(value, expanded_defs)?; self.date.insert(name, data); Some(()) } - fn parse_number_field(&mut self, name: &str, value: &Value) -> Option<()> { + fn parse_number_field(&mut self, name: &str, value: &Value, expanded_defs: &FieldParseCache) -> Option<()> { let name = NumberField::parse(name)?; - let data = NumberFieldData::parse(value)?; + let data = NumberFieldData::parse(value, expanded_defs)?; self.number.insert(name, data); Some(()) } - fn parse_text_field(&mut self, name: &str, value: &Value) -> Option<()> { + fn parse_text_field(&mut self, name: &str, value: &Value, expanded_defs: &FieldParseCache) -> Option<()> { let name = TextField::parse(name).unwrap_or(TextField::Unknown); - let data = TextFieldData::parse(value)?; + let data = TextFieldData::parse(value, expanded_defs)?; self.text.insert(name, data); Some(()) } diff --git a/support/texlab/crates/citeproc/src/lib.rs b/support/texlab/crates/citeproc/src/lib.rs index de24306583..915d3d69ba 100644 --- a/support/texlab/crates/citeproc/src/lib.rs +++ b/support/texlab/crates/citeproc/src/lib.rs @@ -2,16 +2,17 @@ mod driver; mod entry; mod output; +use base_db::semantics::bib::Semantics; use syntax::bibtex; use unicode_normalization::UnicodeNormalization; use self::{driver::Driver, output::Inline}; #[must_use] -pub fn render(entry: &bibtex::Entry) -> Option<String> { +pub fn render(entry: &bibtex::Entry, semantics: &Semantics) -> Option<String> { let mut output = String::new(); let mut driver = Driver::default(); - driver.process(entry); + driver.process(entry, semantics); driver.finish().for_each(|(inline, punct)| { let text = match inline { Inline::Regular(text) => text, diff --git a/support/texlab/crates/citeproc/src/tests.rs b/support/texlab/crates/citeproc/src/tests.rs index 1c91580f39..b5838b52b5 100644 --- a/support/texlab/crates/citeproc/src/tests.rs +++ b/support/texlab/crates/citeproc/src/tests.rs @@ -1,3 +1,4 @@ +use base_db::semantics::bib::Semantics; use expect_test::{expect, Expect}; use parser::parse_bibtex; use rowan::ast::AstNode; @@ -5,9 +6,12 @@ use syntax::bibtex; fn check(input: &str, expect: Expect) { let green = parse_bibtex(input); - let root = bibtex::Root::cast(bibtex::SyntaxNode::new_root(green)).unwrap(); + let root = bibtex::SyntaxNode::new_root(green); + let mut semantics = Semantics::default(); + semantics.process_root(&root); + let root = bibtex::Root::cast(root).unwrap(); let entry = root.entries().next().unwrap(); - let output = super::render(&entry).unwrap(); + let output = super::render(&entry, &semantics).unwrap(); expect.assert_eq(&output); } diff --git a/support/texlab/crates/commands/Cargo.toml b/support/texlab/crates/commands/Cargo.toml index c54d77abf4..512a05ee61 100644 --- a/support/texlab/crates/commands/Cargo.toml +++ b/support/texlab/crates/commands/Cargo.toml @@ -9,15 +9,15 @@ rust-version.workspace = true [dependencies] anyhow = "1.0.72" base-db = { path = "../base-db" } -bstr = "1.8.0" +bstr = "1.9.0" crossbeam-channel = "0.5.11" itertools = "0.12.0" -libc = "0.2.150" -log = "0.4.19" +libc = "0.2.153" +log = "0.4.21" rowan = "0.15.15" rustc-hash = "1.1.0" syntax = { path = "../syntax" } -thiserror = "1.0.56" +thiserror = "1.0.57" url = "2.5.0" [dev-dependencies] diff --git a/support/texlab/crates/completion-data/Cargo.toml b/support/texlab/crates/completion-data/Cargo.toml index c32c02d3bc..37ecf1b3cf 100644 --- a/support/texlab/crates/completion-data/Cargo.toml +++ b/support/texlab/crates/completion-data/Cargo.toml @@ -12,7 +12,7 @@ itertools = "0.12.0" once_cell = "1.19.0" rustc-hash = "1.1.0" serde = { version = "1.0.195", features = ["derive"] } -serde_json = "1.0.108" +serde_json = "1.0.114" [lib] doctest = false diff --git a/support/texlab/crates/completion/Cargo.toml b/support/texlab/crates/completion/Cargo.toml index 5bcebea435..fbdd2d7201 100644 --- a/support/texlab/crates/completion/Cargo.toml +++ b/support/texlab/crates/completion/Cargo.toml @@ -11,7 +11,7 @@ base-db = { path = "../base-db" } completion-data = { path = "../completion-data" } fuzzy-matcher = { version = "0.3.7", features = ["compact"] } line-index = { path = "../line-index" } -rayon = "1.7.0" +rayon = "1.8.1" rowan = "0.15.15" rustc-hash = "1.1.0" syntax = { path = "../syntax" } diff --git a/support/texlab/crates/diagnostics/Cargo.toml b/support/texlab/crates/diagnostics/Cargo.toml index 1fb4b2171d..91c2ff9dbd 100644 --- a/support/texlab/crates/diagnostics/Cargo.toml +++ b/support/texlab/crates/diagnostics/Cargo.toml @@ -14,8 +14,8 @@ encoding_rs = "0.8.33" encoding_rs_io = "0.1.7" itertools = "0.12.0" line-index = { path = "../line-index" } -log = "0.4.20" -multimap = "0.9.1" +log = "0.4.21" +multimap = "0.10.0" once_cell = "1.19.0" parking_lot = "0.12.1" regex = "1.10.2" diff --git a/support/texlab/crates/diagnostics/src/citations.rs b/support/texlab/crates/diagnostics/src/citations.rs index 403d2f5bfc..ea4ef03d58 100644 --- a/support/texlab/crates/diagnostics/src/citations.rs +++ b/support/texlab/crates/diagnostics/src/citations.rs @@ -3,8 +3,7 @@ use base_db::{ util::queries::{self, Object}, Document, Project, Workspace, }; -use multimap::MultiMap; -use rustc_hash::FxHashSet; +use rustc_hash::{FxHashMap, FxHashSet}; use url::Url; use crate::types::{BibError, Diagnostic, TexError}; @@ -14,7 +13,7 @@ const MAX_UNUSED_ENTRIES: usize = 1000; pub fn detect_undefined_citations<'a>( project: &Project<'a>, document: &'a Document, - results: &mut MultiMap<Url, Diagnostic>, + results: &mut FxHashMap<Url, Vec<Diagnostic>>, ) -> Option<()> { let data = document.data.as_tex()?; @@ -26,7 +25,10 @@ pub fn detect_undefined_citations<'a>( let name = citation.name_text(); if name != "*" && !entries.contains(name) { let diagnostic = Diagnostic::Tex(citation.name.range, TexError::UndefinedCitation); - results.insert(document.uri.clone(), diagnostic); + results + .entry(document.uri.clone()) + .or_default() + .push(diagnostic); } } @@ -36,7 +38,7 @@ pub fn detect_undefined_citations<'a>( pub fn detect_unused_entries<'a>( project: &Project<'a>, document: &'a Document, - results: &mut MultiMap<Url, Diagnostic>, + results: &mut FxHashMap<Url, Vec<Diagnostic>>, ) -> Option<()> { let data = document.data.as_bib()?; @@ -52,7 +54,10 @@ pub fn detect_unused_entries<'a>( for entry in &data.semantics.entries { if !citations.contains(entry.name.text.as_str()) { let diagnostic = Diagnostic::Bib(entry.name.range, BibError::UnusedEntry); - results.insert(document.uri.clone(), diagnostic); + results + .entry(document.uri.clone()) + .or_default() + .push(diagnostic); } } @@ -61,7 +66,7 @@ pub fn detect_unused_entries<'a>( pub fn detect_duplicate_entries<'a>( workspace: &'a Workspace, - results: &mut MultiMap<Url, Diagnostic>, + results: &mut FxHashMap<Url, Vec<Diagnostic>>, ) { for conflict in queries::Conflict::find_all::<Entry>(workspace) { let others = conflict @@ -71,6 +76,9 @@ pub fn detect_duplicate_entries<'a>( .collect(); let diagnostic = Diagnostic::Bib(conflict.main.range, BibError::DuplicateEntry(others)); - results.insert(conflict.main.document.uri.clone(), diagnostic); + results + .entry(conflict.main.document.uri.clone()) + .or_default() + .push(diagnostic); } } diff --git a/support/texlab/crates/diagnostics/src/labels.rs b/support/texlab/crates/diagnostics/src/labels.rs index 92f9072918..9a39f3f24b 100644 --- a/support/texlab/crates/diagnostics/src/labels.rs +++ b/support/texlab/crates/diagnostics/src/labels.rs @@ -4,15 +4,14 @@ use base_db::{ DocumentData, Workspace, }; use itertools::Itertools; -use multimap::MultiMap; -use rustc_hash::FxHashSet; +use rustc_hash::{FxHashMap, FxHashSet}; use url::Url; use crate::types::{Diagnostic, TexError}; pub fn detect_undefined_and_unused_labels( workspace: &Workspace, - results: &mut MultiMap<Url, Diagnostic>, + results: &mut FxHashMap<Url, Vec<Diagnostic>>, ) { let graphs: Vec<_> = workspace .iter() @@ -45,18 +44,27 @@ pub fn detect_undefined_and_unused_labels( for label in &data.semantics.labels { if label.kind != LabelKind::Definition && !label_defs.contains(&label.name.text) { let diagnostic = Diagnostic::Tex(label.name.range, TexError::UndefinedLabel); - results.insert(document.uri.clone(), diagnostic); + results + .entry(document.uri.clone()) + .or_default() + .push(diagnostic); } if label.kind == LabelKind::Definition && !label_refs.contains(&label.name.text) { let diagnostic = Diagnostic::Tex(label.name.range, TexError::UnusedLabel); - results.insert(document.uri.clone(), diagnostic); + results + .entry(document.uri.clone()) + .or_default() + .push(diagnostic); } } } } -pub fn detect_duplicate_labels(workspace: &Workspace, results: &mut MultiMap<Url, Diagnostic>) { +pub fn detect_duplicate_labels( + workspace: &Workspace, + results: &mut FxHashMap<Url, Vec<Diagnostic>>, +) { for conflict in queries::Conflict::find_all::<Label>(workspace) { let others = conflict .rest @@ -65,6 +73,9 @@ pub fn detect_duplicate_labels(workspace: &Workspace, results: &mut MultiMap<Url .collect(); let diagnostic = Diagnostic::Tex(conflict.main.range, TexError::DuplicateLabel(others)); - results.insert(conflict.main.document.uri.clone(), diagnostic); + results + .entry(conflict.main.document.uri.clone()) + .or_default() + .push(diagnostic); } } diff --git a/support/texlab/crates/diagnostics/src/manager.rs b/support/texlab/crates/diagnostics/src/manager.rs index 1ce5e194b8..38c0a514f4 100644 --- a/support/texlab/crates/diagnostics/src/manager.rs +++ b/support/texlab/crates/diagnostics/src/manager.rs @@ -16,6 +16,10 @@ pub struct Manager { impl Manager { /// Updates the syntax-based diagnostics for the given document. pub fn update_syntax(&mut self, workspace: &Workspace, document: &Document) { + if !Self::is_relevant(document) { + return; + } + self.grammar.remove(&document.uri); super::grammar::tex::update(document, workspace.config(), &mut self.grammar); super::grammar::bib::update(document, &mut self.grammar); @@ -30,14 +34,20 @@ impl Manager { } /// Returns all filtered diagnostics for the given workspace. - pub fn get(&self, workspace: &Workspace) -> MultiMap<Url, Diagnostic> { - let mut results = MultiMap::default(); + pub fn get(&self, workspace: &Workspace) -> FxHashMap<Url, Vec<Diagnostic>> { + let mut results: FxHashMap<Url, Vec<Diagnostic>> = FxHashMap::default(); for (uri, diagnostics) in &self.grammar { - results.insert_many_from_slice(uri.clone(), diagnostics); + results + .entry(uri.clone()) + .or_default() + .extend(diagnostics.iter().cloned()); } for (uri, diagnostics) in self.build_log.values().flatten() { - results.insert_many_from_slice(uri.clone(), diagnostics); + results + .entry(uri.clone()) + .or_default() + .extend(diagnostics.iter().cloned()); } for (uri, diagnostics) in &self.chktex { @@ -45,11 +55,17 @@ impl Manager { .lookup(uri) .map_or(false, |document| document.owner == Owner::Client) { - results.insert_many_from_slice(uri.clone(), diagnostics); + results + .entry(uri.clone()) + .or_default() + .extend(diagnostics.iter().cloned()); } } - for document in workspace.iter() { + for document in workspace + .iter() + .filter(|document| Self::is_relevant(document)) + { let project = workspace.project(document); super::citations::detect_undefined_citations(&project, document, &mut results); super::citations::detect_unused_entries(&project, document, &mut results); @@ -60,6 +76,13 @@ impl Manager { super::labels::detect_undefined_and_unused_labels(workspace, &mut results); let config = &workspace.config().diagnostics; + + results.retain(|uri, _| { + workspace + .lookup(uri) + .map_or(false, |document| Self::is_relevant(document)) + }); + for (_, diagnostics) in &mut results { diagnostics.retain(|diagnostic| { filter_regex_patterns( @@ -72,4 +95,12 @@ impl Manager { results } + + fn is_relevant(document: &Document) -> bool { + match document.owner { + Owner::Client => true, + Owner::Server => true, + Owner::Distro => false, + } + } } diff --git a/support/texlab/crates/diagnostics/src/tests.rs b/support/texlab/crates/diagnostics/src/tests.rs index b7c6004d19..3688abeaf4 100644 --- a/support/texlab/crates/diagnostics/src/tests.rs +++ b/support/texlab/crates/diagnostics/src/tests.rs @@ -11,7 +11,7 @@ fn check(input: &str, expect: Expect) { let results = manager.get(&fixture.workspace); let results = results - .iter_all() + .iter() .filter(|(_, diags)| !diags.is_empty()) .sorted_by(|(uri1, _), (uri2, _)| uri1.cmp(&uri2)) .map(|(uri, diags)| (uri.as_str(), diags)) diff --git a/support/texlab/crates/distro/src/file_name_db.rs b/support/texlab/crates/distro/src/file_name_db.rs index 06871bde83..fd6750fffa 100644 --- a/support/texlab/crates/distro/src/file_name_db.rs +++ b/support/texlab/crates/distro/src/file_name_db.rs @@ -55,6 +55,11 @@ impl FileNameDB { self.files.get(name).map(|file| file.path()) } + pub fn contains(&self, path: &Path) -> bool { + let name = path.file_name().unwrap().to_str().unwrap(); + self.get(name) == Some(path) + } + pub fn iter(&self) -> impl Iterator<Item = (&str, &Path)> + '_ { self.files.iter().map(|file| (file.name(), file.path())) } diff --git a/support/texlab/crates/hover/src/citation.rs b/support/texlab/crates/hover/src/citation.rs index 372668997e..a39ea2e5f5 100644 --- a/support/texlab/crates/hover/src/citation.rs +++ b/support/texlab/crates/hover/src/citation.rs @@ -31,7 +31,7 @@ pub(super) fn find_hover<'a>(params: &HoverParams<'a>) -> Option<Hover<'a>> { let data = document.data.as_bib()?; let root = bibtex::Root::cast(data.root_node())?; let entry = root.find_entry(name)?; - citeproc::render(&entry) + citeproc::render(&entry, &data.semantics) })?; let data = HoverData::Citation(text); diff --git a/support/texlab/crates/hover/src/string_ref.rs b/support/texlab/crates/hover/src/string_ref.rs index 6726041af2..cf8062a5a0 100644 --- a/support/texlab/crates/hover/src/string_ref.rs +++ b/support/texlab/crates/hover/src/string_ref.rs @@ -24,7 +24,7 @@ pub(super) fn find_hover<'a>(params: &HoverParams<'a>) -> Option<Hover<'a>> { continue; } - let value = TextFieldData::parse(&string.value()?)?.text; + let value = TextFieldData::parse(&string.value()?, &data.semantics.expanded_defs)?.text; return Some(Hover { range: name.text_range(), data: HoverData::StringRef(value), diff --git a/support/texlab/crates/parser/Cargo.toml b/support/texlab/crates/parser/Cargo.toml index c3e31b7022..0fd8889899 100644 --- a/support/texlab/crates/parser/Cargo.toml +++ b/support/texlab/crates/parser/Cargo.toml @@ -13,7 +13,7 @@ regex = "1.10.2" rowan = "0.15.15" rustc-hash = "1.1.0" syntax = { path = "../syntax" } -tempfile = "3.8.1" +tempfile = "3.10.1" [dev-dependencies] expect-test = "1.4.1" diff --git a/support/texlab/crates/parser/src/config.rs b/support/texlab/crates/parser/src/config.rs index 3a2e9e3e93..6537d21b0d 100644 --- a/support/texlab/crates/parser/src/config.rs +++ b/support/texlab/crates/parser/src/config.rs @@ -7,6 +7,7 @@ pub struct SyntaxConfig { pub enum_environments: FxHashSet<String>, pub verbatim_environments: FxHashSet<String>, pub citation_commands: FxHashSet<String>, + pub label_reference_commands: FxHashSet<String>, } impl Default for SyntaxConfig { @@ -31,12 +32,18 @@ impl Default for SyntaxConfig { .map(ToString::to_string) .collect(); + let label_reference_commands = DEFAULT_LABEL_REFERENCE_COMMANDS + .iter() + .map(ToString::to_string) + .collect(); + Self { follow_package_links: false, math_environments, enum_environments, verbatim_environments, citation_commands, + label_reference_commands, } } } @@ -155,3 +162,24 @@ static DEFAULT_CITATION_COMMANDS: &[&str] = &[ "citeA", "citeA*", ]; + +static DEFAULT_LABEL_REFERENCE_COMMANDS: &[&str] = &[ + "ref", + "vref", + "Vref", + "autoref", + "pageref", + "cref", + "cref*", + "Cref", + "Cref*", + "namecref", + "nameCref", + "lcnamecref", + "namecrefs", + "nameCrefs", + "lcnamecrefs", + "labelcref", + "labelcpageref", + "eqref", +]; diff --git a/support/texlab/crates/parser/src/latex.rs b/support/texlab/crates/parser/src/latex.rs index d88eb39556..4a6fabae21 100644 --- a/support/texlab/crates/parser/src/latex.rs +++ b/support/texlab/crates/parser/src/latex.rs @@ -25,6 +25,13 @@ impl Default for ParserContext { } } +#[derive(Debug, Clone, Copy)] +struct KeyOptions { + allow_eq: bool, + allow_parens: bool, + allow_bracks: bool, +} + #[derive(Debug)] struct Parser<'a> { lexer: Lexer<'a>, @@ -309,7 +316,11 @@ impl<'a> Parser<'a> { self.trivia(); match self.peek() { Some(Token::Word | Token::Pipe) => { - self.key(); + self.key_with_opts(KeyOptions { + allow_eq: true, + allow_bracks: false, + allow_parens: true, + }); } Some(_) | None => {} } @@ -340,16 +351,22 @@ impl<'a> Parser<'a> { } fn key(&mut self) { - self.key_with_eq(true); + self.key_with_opts(KeyOptions { + allow_eq: true, + allow_parens: true, + allow_bracks: true, + }); } - fn key_with_eq(&mut self, allow_eq: bool) { + fn key_with_opts(&mut self, options: KeyOptions) { self.builder.start_node(KEY.into()); self.eat(); while let Some(kind) = self.peek() { match kind { Token::Whitespace | Token::LineComment | Token::Word | Token::Pipe => self.eat(), - Token::Eq if allow_eq => self.eat(), + Token::LBrack | Token::RBrack if options.allow_bracks => self.eat(), + Token::LParen | Token::RParen if options.allow_parens => self.eat(), + Token::Eq if options.allow_eq => self.eat(), _ => break, } } @@ -374,7 +391,12 @@ impl<'a> Parser<'a> { fn key_value_pair(&mut self) { self.builder.start_node(KEY_VALUE_PAIR.into()); - self.key_with_eq(false); + self.key_with_opts(KeyOptions { + allow_eq: false, + allow_parens: true, + allow_bracks: false, + }); + if self.peek() == Some(Token::Eq) { self.eat(); self.trivia(); diff --git a/support/texlab/crates/parser/src/latex/lexer/commands.rs b/support/texlab/crates/parser/src/latex/lexer/commands.rs index b6e1d11737..95eef4becd 100644 --- a/support/texlab/crates/parser/src/latex/lexer/commands.rs +++ b/support/texlab/crates/parser/src/latex/lexer/commands.rs @@ -30,9 +30,6 @@ pub fn classify(name: &str, config: &SyntaxConfig) -> CommandName { CommandName::Import } "label" => CommandName::LabelDefinition, - "ref" | "vref" | "Vref" | "autoref" | "pageref" | "cref" | "cref*" | "Cref" | "Cref*" - | "namecref" | "nameCref" | "lcnamecref" | "namecrefs" | "nameCrefs" | "lcnamecrefs" - | "labelcref" | "labelcpageref" | "eqref" => CommandName::LabelReference, "crefrange" | "crefrange*" | "Crefrange" | "Crefrange*" => CommandName::LabelReferenceRange, "newlabel" => CommandName::LabelNumber, "newcommand" @@ -81,6 +78,7 @@ pub fn classify(name: &str, config: &SyntaxConfig) -> CommandName { "fi" => CommandName::EndBlockComment, "verb" => CommandName::VerbatimBlock, _ if config.citation_commands.contains(name) => CommandName::Citation, + _ if config.label_reference_commands.contains(name) => CommandName::LabelReference, _ => CommandName::Generic, } } diff --git a/support/texlab/crates/parser/src/latex/tests.rs b/support/texlab/crates/parser/src/latex/tests.rs index 6e5019776f..5e1a4044cd 100644 --- a/support/texlab/crates/parser/src/latex/tests.rs +++ b/support/texlab/crates/parser/src/latex/tests.rs @@ -3542,3 +3542,72 @@ fn test_command_subscript() { "#]], ); } + +#[test] +fn test_label_parens() { + check( + r#"\label{foo (bar)}"#, + expect![[r#" + ROOT@0..17 + PREAMBLE@0..17 + LABEL_DEFINITION@0..17 + COMMAND_NAME@0..6 "\\label" + CURLY_GROUP_WORD@6..17 + L_CURLY@6..7 "{" + KEY@7..16 + WORD@7..10 "foo" + WHITESPACE@10..11 " " + L_PAREN@11..12 "(" + WORD@12..15 "bar" + R_PAREN@15..16 ")" + R_CURLY@16..17 "}" + + "#]], + ); +} + +#[test] +fn test_label_brackets() { + check( + r#"\label{foo [bar]}"#, + expect![[r#" + ROOT@0..17 + PREAMBLE@0..17 + LABEL_DEFINITION@0..17 + COMMAND_NAME@0..6 "\\label" + CURLY_GROUP_WORD@6..17 + L_CURLY@6..7 "{" + KEY@7..16 + WORD@7..10 "foo" + WHITESPACE@10..11 " " + L_BRACK@11..12 "[" + WORD@12..15 "bar" + R_BRACK@15..16 "]" + R_CURLY@16..17 "}" + + "#]], + ); +} + +#[test] +fn test_label_brackets_unbalanced() { + check( + r#"\label{foo ]bar[}"#, + expect![[r#" + ROOT@0..17 + PREAMBLE@0..17 + LABEL_DEFINITION@0..17 + COMMAND_NAME@0..6 "\\label" + CURLY_GROUP_WORD@6..17 + L_CURLY@6..7 "{" + KEY@7..16 + WORD@7..10 "foo" + WHITESPACE@10..11 " " + R_BRACK@11..12 "]" + WORD@12..15 "bar" + L_BRACK@15..16 "[" + R_CURLY@16..17 "}" + + "#]], + ); +} diff --git a/support/texlab/crates/texlab/Cargo.toml b/support/texlab/crates/texlab/Cargo.toml index 53b63ded3e..ccc02bff01 100644 --- a/support/texlab/crates/texlab/Cargo.toml +++ b/support/texlab/crates/texlab/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "texlab" description = "LaTeX Language Server" -version = "5.12.3" +version = "5.13.1" license.workspace = true readme = "README.md" authors.workspace = true @@ -26,7 +26,7 @@ anyhow = "1.0.75" base-db = { path = "../base-db" } bibfmt = { path = "../bibfmt" } citeproc = { path = "../citeproc" } -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.18", features = ["derive"] } commands = { path = "../commands" } completion = { path = "../completion" } completion-data = { path = "../completion-data" } @@ -43,9 +43,9 @@ hover = { path = "../hover" } inlay-hints = { path = "../inlay-hints" } line-index = { path = "../line-index" } links = { path = "../links" } -log = "0.4.19" +log = "0.4.21" lsp-server = "0.7.6" -lsp-types = "0.94.1" +lsp-types = "0.95.0" notify = "6.1.1" notify-debouncer-full = "0.3.1" once_cell = "1.19.0" @@ -57,12 +57,12 @@ rename = { path = "../rename" } rowan = "0.15.15" rustc-hash = "1.1.0" serde = "1.0.195" -serde_json = "1.0.108" +serde_json = "1.0.114" serde_regex = "1.1.0" -serde_repr = "0.1.17" +serde_repr = "0.1.18" symbols = { path = "../symbols" } syntax = { path = "../syntax" } -tempfile = "3.8.0" +tempfile = "3.10.1" threadpool = "1.8.1" [dev-dependencies] diff --git a/support/texlab/crates/texlab/src/client.rs b/support/texlab/crates/texlab/src/client.rs index 9bbace9938..b79f876436 100644 --- a/support/texlab/crates/texlab/src/client.rs +++ b/support/texlab/crates/texlab/src/client.rs @@ -93,8 +93,14 @@ impl LspClient { Ok(()) } - pub fn parse_options(&self, value: serde_json::Value) -> Result<Options> { - let options = match serde_json::from_value(value) { + pub fn parse_options(&self, mut value: serde_json::Value) -> Result<Options> { + // if there are multiple servers, we need to extract the options for texlab first + let options = match value.get_mut("texlab") { + Some(section) => section.take(), + None => value, + }; + + let options = match serde_json::from_value(options) { Ok(new_options) => new_options, Err(why) => { let message = format!( diff --git a/support/texlab/crates/texlab/src/features/completion.rs b/support/texlab/crates/texlab/src/features/completion.rs index 5d32588970..5bca0070ef 100644 --- a/support/texlab/crates/texlab/src/features/completion.rs +++ b/support/texlab/crates/texlab/src/features/completion.rs @@ -1,4 +1,4 @@ -use base_db::{util::RenderedObject, Workspace}; +use base_db::{util::RenderedObject, MatchingAlgo, Workspace}; use completion::{ArgumentData, CompletionItem, CompletionItemData, EntryTypeData, FieldTypeData}; use line_index::LineIndex; use rowan::ast::AstNode; @@ -20,8 +20,16 @@ pub fn complete( client_flags, }; - let is_incomplete = - client_flags.completion_always_incomplete || result.items.len() >= completion::LIMIT; + let is_fuzzy = match workspace.config().completion.matcher { + MatchingAlgo::Skim => true, + MatchingAlgo::SkimIgnoreCase => true, + MatchingAlgo::Prefix => false, + MatchingAlgo::PrefixIgnoreCase => false, + }; + + let is_incomplete = client_flags.completion_always_incomplete + || !is_fuzzy + || result.items.len() >= completion::LIMIT; let items = result .items @@ -53,7 +61,7 @@ pub fn resolve(workspace: &Workspace, item: &mut lsp_types::CompletionItem) -> O let data = workspace.lookup(&uri)?.data.as_bib()?; let root = bibtex::Root::cast(data.root_node())?; let entry = root.find_entry(&key)?; - let value = citeproc::render(&entry)?; + let value = citeproc::render(&entry, &data.semantics)?; item.documentation = Some(lsp_types::Documentation::MarkupContent( lsp_types::MarkupContent { kind: lsp_types::MarkupKind::Markdown, diff --git a/support/texlab/crates/texlab/src/server.rs b/support/texlab/crates/texlab/src/server.rs index 0fb186f688..fc16775bc9 100644 --- a/support/texlab/crates/texlab/src/server.rs +++ b/support/texlab/crates/texlab/src/server.rs @@ -813,7 +813,7 @@ impl Server { .map_or(true, |document| document.owner == Owner::Server) { if let Some(language) = Language::from_path(&path) { - changed |= workspace.load(&path, language, Owner::Server).is_ok(); + changed |= workspace.load(&path, language).is_ok(); if let Some(document) = workspace.lookup_path(&path) { self.diagnostic_manager.update_syntax(&workspace, document); diff --git a/support/texlab/crates/texlab/src/server/options.rs b/support/texlab/crates/texlab/src/server/options.rs index 72b2b127fb..60c0bf90f7 100644 --- a/support/texlab/crates/texlab/src/server/options.rs +++ b/support/texlab/crates/texlab/src/server/options.rs @@ -128,6 +128,7 @@ pub struct ExperimentalOptions { pub enum_environments: Vec<String>, pub verbatim_environments: Vec<String>, pub citation_commands: Vec<String>, + pub label_reference_commands: Vec<String>, } #[derive(Debug, PartialEq, Eq, Clone, Default, Serialize, Deserialize)] @@ -283,5 +284,10 @@ impl From<Options> for Config { .extend(value.experimental.citation_commands); config + .syntax + .label_reference_commands + .extend(value.experimental.label_reference_commands); + + config } } diff --git a/support/texlab/texlab.1 b/support/texlab/texlab.1 index ea5ac6ec05..10a9e2d48d 100644 --- a/support/texlab/texlab.1 +++ b/support/texlab/texlab.1 @@ -1,7 +1,7 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.13. -.TH TEXLAB "1" "January 2024" "texlab 5.12.3" "User Commands" +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.1. +.TH TEXLAB "1" "March 2024" "texlab 5.13.1" "User Commands" .SH NAME -texlab \- manual page for texlab 5.12.3 +texlab \- manual page for texlab 5.13.1 .SH SYNOPSIS .B texlab [\fI\,OPTIONS\/\fR] diff --git a/support/texlab/texlab.pdf b/support/texlab/texlab.pdf Binary files differindex 6e2ddb1b35..efbde26dd6 100644 --- a/support/texlab/texlab.pdf +++ b/support/texlab/texlab.pdf |