@@ -927,12 +927,86 @@ unsigned char Editline::BufferEndCommand(int ch) {
927
927
static void
928
928
PrintCompletion (FILE *output_file,
929
929
llvm::ArrayRef<CompletionResult::Completion> results,
930
- size_t max_len) {
930
+ size_t max_completion_length, size_t max_length) {
931
+ constexpr size_t ellipsis_length = 3 ;
932
+ constexpr size_t padding_length = 8 ;
933
+ constexpr size_t separator_length = 4 ;
934
+
935
+ const size_t description_col =
936
+ std::min (max_completion_length + padding_length, max_length);
937
+
931
938
for (const CompletionResult::Completion &c : results) {
932
- fprintf (output_file, " \t %-*s" , (int )max_len, c.GetCompletion ().c_str ());
933
- if (!c.GetDescription ().empty ())
934
- fprintf (output_file, " -- %s" , c.GetDescription ().c_str ());
935
- fprintf (output_file, " \n " );
939
+ if (c.GetCompletion ().empty ())
940
+ continue ;
941
+
942
+ // Print the leading padding.
943
+ fprintf (output_file, " " );
944
+
945
+ // Print the completion with trailing padding to the description column if
946
+ // that fits on the screen. Otherwise print whatever fits on the screen
947
+ // followed by ellipsis.
948
+ const size_t completion_length = c.GetCompletion ().size ();
949
+ if (padding_length + completion_length < max_length) {
950
+ fprintf (output_file, " %-*s" ,
951
+ static_cast <int >(description_col - padding_length),
952
+ c.GetCompletion ().c_str ());
953
+ } else {
954
+ // If the completion doesn't fit on the screen, print ellipsis and don't
955
+ // bother with the description.
956
+ fprintf (output_file, " %.*s...\n " ,
957
+ static_cast <int >(max_length - padding_length - ellipsis_length),
958
+ c.GetCompletion ().c_str ());
959
+ continue ;
960
+ }
961
+
962
+ // If we don't have a description, or we don't have enough space left to
963
+ // print the separator followed by the ellipsis, we're done.
964
+ if (c.GetDescription ().empty () ||
965
+ description_col + separator_length + ellipsis_length >= max_length) {
966
+ fprintf (output_file, " \n " );
967
+ continue ;
968
+ }
969
+
970
+ // Print the separator.
971
+ fprintf (output_file, " -- " );
972
+
973
+ // Descriptions can contain newlines. We want to print them below each
974
+ // other, aligned after the separator. For example, foo has a
975
+ // two-line description:
976
+ //
977
+ // foo -- Something that fits on the line.
978
+ // More information below.
979
+ //
980
+ // However, as soon as a line exceed the available screen width and
981
+ // print ellipsis, we don't print the next line. For example, foo has a
982
+ // three-line description:
983
+ //
984
+ // foo -- Something that fits on the line.
985
+ // Something much longer that doesn't fit...
986
+ //
987
+ // Because we had to print ellipsis on line two, we don't print the
988
+ // third line.
989
+ bool first = true ;
990
+ for (llvm::StringRef line : llvm::split (c.GetDescription (), ' \n ' )) {
991
+ if (line.empty ())
992
+ break ;
993
+ if (!first)
994
+ fprintf (output_file, " %*s" ,
995
+ static_cast <int >(description_col + separator_length), " " );
996
+
997
+ first = false ;
998
+ const size_t position = description_col + separator_length;
999
+ const size_t description_length = line.size ();
1000
+ if (position + description_length < max_length) {
1001
+ fprintf (output_file, " %.*s\n " , static_cast <int >(description_length),
1002
+ line.data ());
1003
+ } else {
1004
+ fprintf (output_file, " %.*s...\n " ,
1005
+ static_cast <int >(max_length - position - ellipsis_length),
1006
+ line.data ());
1007
+ continue ;
1008
+ }
1009
+ }
936
1010
}
937
1011
}
938
1012
@@ -953,7 +1027,8 @@ void Editline::DisplayCompletions(
953
1027
const size_t max_len = longest->GetCompletion ().size ();
954
1028
955
1029
if (results.size () < page_size) {
956
- PrintCompletion (editline.m_output_file , results, max_len);
1030
+ PrintCompletion (editline.m_output_file , results, max_len,
1031
+ editline.GetTerminalWidth ());
957
1032
return ;
958
1033
}
959
1034
@@ -963,7 +1038,7 @@ void Editline::DisplayCompletions(
963
1038
size_t next_size = all ? remaining : std::min (page_size, remaining);
964
1039
965
1040
PrintCompletion (editline.m_output_file , results.slice (cur_pos, next_size),
966
- max_len);
1041
+ max_len, editline. GetTerminalWidth () );
967
1042
968
1043
cur_pos += next_size;
969
1044
0 commit comments