@@ -7,10 +7,13 @@ import (
77 "bytes"
88 "encoding/json"
99 "fmt"
10+ "os"
1011 "reflect"
1112 "sort"
1213 "strings"
1314 "text/tabwriter"
15+
16+ "golang.org/x/term"
1417)
1518
1619// OutputFormat represents the available output format options.
@@ -108,6 +111,7 @@ func formatTable(data any) (string, error) {
108111 return formatGenericMap (mapVal )
109112}
110113
114+ // formatToolsList formats a list of tools as a table
111115func formatToolsList (tools any ) (string , error ) {
112116 toolsSlice , ok := tools .([]any )
113117 if ! ok {
@@ -119,11 +123,19 @@ func formatToolsList(tools any) (string, error) {
119123 }
120124
121125 var buf bytes.Buffer
122- w := tabwriter .NewWriter (& buf , 0 , 0 , 2 , ' ' , 0 )
126+ w := tabwriter .NewWriter (& buf , 0 , 0 , 2 , ' ' , tabwriter . StripEscape )
123127
124128 fmt .Fprintln (w , "NAME\t DESCRIPTION" )
125129 fmt .Fprintln (w , "----\t -----------" )
126130
131+ termWidth := getTermWidth ()
132+ nameColWidth := 20 // Default name column width
133+ descColWidth := termWidth - nameColWidth - 5 // Leave some margin
134+
135+ if descColWidth < 10 {
136+ descColWidth = 40 // Minimum width if terminal is too narrow
137+ }
138+
127139 for _ , t := range toolsSlice {
128140 tool , ok1 := t .(map [string ]any )
129141 if ! ok1 {
@@ -133,17 +145,77 @@ func formatToolsList(tools any) (string, error) {
133145 name , _ := tool ["name" ].(string )
134146 desc , _ := tool ["description" ].(string )
135147
136- if len (desc ) > 70 {
137- desc = desc [:67 ] + "..."
148+ // Handle multiline description
149+ lines := wrapText (desc , descColWidth )
150+
151+ if len (lines ) == 0 {
152+ fmt .Fprintf (w , "%s\t \n " , name )
153+ continue
154+ }
155+
156+ // First line with name
157+ fmt .Fprintf (w , "%s\t %s\n " , name , lines [0 ])
158+
159+ // Remaining lines with empty name column
160+ for _ , line := range lines [1 :] {
161+ fmt .Fprintf (w , "\t %s\n " , line )
162+ }
163+
164+ // Add a blank line between entries
165+ if len (lines ) > 1 {
166+ fmt .Fprintln (w , "\t " )
138167 }
139-
140- fmt .Fprintf (w , "%s\t %s\n " , name , desc )
141168 }
142169
143170 _ = w .Flush ()
144171 return buf .String (), nil
145172}
146173
174+ // getTermWidth returns the terminal width or a default value if detection fails
175+ func getTermWidth () int {
176+ width , _ , err := term .GetSize (int (os .Stdout .Fd ()))
177+ if err != nil || width <= 0 {
178+ return 80 // Default width if terminal width cannot be determined
179+ }
180+ return width
181+ }
182+
183+ // wrapText wraps text to fit within a specified width
184+ func wrapText (text string , width int ) []string {
185+ if text == "" {
186+ return []string {}
187+ }
188+
189+ words := strings .Fields (text )
190+ if len (words ) == 0 {
191+ return []string {}
192+ }
193+
194+ var lines []string
195+ var currentLine string
196+
197+ for _ , word := range words {
198+ // Check if adding this word would exceed the width
199+ if len (currentLine )+ len (word )+ 1 > width && len (currentLine ) > 0 {
200+ // Add current line to lines and start a new line
201+ lines = append (lines , currentLine )
202+ currentLine = word
203+ } else if len (currentLine ) == 0 {
204+ currentLine = word
205+ } else {
206+ currentLine += " " + word
207+ }
208+ }
209+
210+ // Add the last line
211+ if len (currentLine ) > 0 {
212+ lines = append (lines , currentLine )
213+ }
214+
215+ return lines
216+ }
217+
218+ // formatResourcesList formats a list of resources as a table
147219func formatResourcesList (resources any ) (string , error ) {
148220 resourcesSlice , ok := resources .([]any )
149221 if ! ok {
@@ -169,14 +241,16 @@ func formatResourcesList(resources any) (string, error) {
169241 name , _ := resource ["name" ].(string )
170242 resType , _ := resource ["type" ].(string )
171243 uri , _ := resource ["uri" ].(string )
172-
244+
245+ // Use the entire URI instead of truncating
173246 fmt .Fprintf (w , "%s\t %s\t %s\n " , name , resType , uri )
174247 }
175248
176249 _ = w .Flush ()
177250 return buf .String (), nil
178251}
179252
253+ // formatPromptsList formats a list of prompts as a table
180254func formatPromptsList (prompts any ) (string , error ) {
181255 promptsSlice , ok := prompts .([]any )
182256 if ! ok {
@@ -188,11 +262,19 @@ func formatPromptsList(prompts any) (string, error) {
188262 }
189263
190264 var buf bytes.Buffer
191- w := tabwriter .NewWriter (& buf , 0 , 0 , 2 , ' ' , 0 )
265+ w := tabwriter .NewWriter (& buf , 0 , 0 , 2 , ' ' , tabwriter . StripEscape )
192266
193267 fmt .Fprintln (w , "NAME\t DESCRIPTION" )
194268 fmt .Fprintln (w , "----\t -----------" )
195269
270+ termWidth := getTermWidth ()
271+ nameColWidth := 20 // Default name column width
272+ descColWidth := termWidth - nameColWidth - 5 // Leave some margin
273+
274+ if descColWidth < 10 {
275+ descColWidth = 40 // Minimum width if terminal is too narrow
276+ }
277+
196278 for _ , p := range promptsSlice {
197279 prompt , ok1 := p .(map [string ]any )
198280 if ! ok1 {
@@ -202,11 +284,26 @@ func formatPromptsList(prompts any) (string, error) {
202284 name , _ := prompt ["name" ].(string )
203285 desc , _ := prompt ["description" ].(string )
204286
205- if len (desc ) > 70 {
206- desc = desc [:67 ] + "..."
287+ // Handle multiline description
288+ lines := wrapText (desc , descColWidth )
289+
290+ if len (lines ) == 0 {
291+ fmt .Fprintf (w , "%s\t \n " , name )
292+ continue
293+ }
294+
295+ // First line with name
296+ fmt .Fprintf (w , "%s\t %s\n " , name , lines [0 ])
297+
298+ // Remaining lines with empty name column
299+ for _ , line := range lines [1 :] {
300+ fmt .Fprintf (w , "\t %s\n " , line )
301+ }
302+
303+ // Add a blank line between entries
304+ if len (lines ) > 1 {
305+ fmt .Fprintln (w , "\t " )
207306 }
208-
209- fmt .Fprintf (w , "%s\t %s\n " , name , desc )
210307 }
211308
212309 _ = w .Flush ()
0 commit comments