@@ -3,6 +3,7 @@ module.exports = exports = search
33
44var npm = require ( "./npm.js" )
55 , registry = npm . registry
6+ , columnify = require ( 'columnify' )
67
78search . usage = "npm search [some search terms ...]"
89
@@ -91,7 +92,8 @@ function stripData (data) {
9192 && ( new Date ( data . time . modified ) . toISOString ( )
9293 . split ( "T" ) . join ( " " )
9394 . replace ( / : [ 0 - 9 ] { 2 } \. [ 0 - 9 ] { 3 } Z $ / , "" ) )
94- || "(prehistoric)"
95+ . slice ( 0 , - 5 ) // remove time
96+ || "prehistoric"
9597 }
9698}
9799
@@ -129,102 +131,77 @@ function match (words, arg) {
129131}
130132
131133function prettify ( data , args ) {
132- try {
133- var tty = require ( "tty" )
134- , stdout = process . stdout
135- , cols = ! tty . isatty ( stdout . fd ) ? Infinity
136- : process . stdout . getWindowSize ( ) [ 0 ]
137- cols = ( cols == 0 ) ? Infinity : cols
138- } catch ( ex ) { cols = Infinity }
139-
140- // name, desc, author, keywords
141- var longest = [ ]
142- , spaces
143- , maxLen = npm . config . get ( "description" )
144- ? [ 20 , 60 , 20 , 20 , 10 , Infinity ]
145- : [ 20 , 20 , 20 , 10 , Infinity ]
146- , headings = npm . config . get ( "description" )
147- ? [ "NAME" , "DESCRIPTION" , "AUTHOR" , "DATE" , "VERSION" , "KEYWORDS" ]
148- : [ "NAME" , "AUTHOR" , "DATE" , "VERSION" , "KEYWORDS" ]
149- , lines
150- , searchsort = ( npm . config . get ( "searchsort" ) || "NAME" ) . toLowerCase ( )
151- , sortFields = { name : 0
152- , description : 1
153- , author : 2
154- , date : 3
155- , version : 4
156- , keywords : 5 }
134+ var searchsort = ( npm . config . get ( "searchsort" ) || "NAME" ) . toLowerCase ( )
135+ , sortField = searchsort . replace ( / ^ \- + / , "" )
157136 , searchRev = searchsort . charAt ( 0 ) === "-"
158- , sortField = sortFields [ searchsort . replace ( / ^ \- + / , "" ) ]
137+ , truncate = ! npm . config . get ( "long" )
138+
139+ if ( Object . keys ( data ) . length === 0 ) {
140+ return "No match found for " + ( args . map ( JSON . stringify ) . join ( " " ) )
141+ }
159142
160- lines = Object . keys ( data ) . map ( function ( d ) {
143+ var lines = Object . keys ( data ) . map ( function ( d ) {
144+ // strip keyname
161145 return data [ d ]
162- } ) . map ( function ( data ) {
163- // turn a pkg data into a string
164- // [name,who,desc,targets,keywords] tuple
165- // also set longest to the longest name
166- if ( typeof data . keywords === "string" ) {
167- data . keywords = data . keywords . split ( / [ , \s ] + / )
146+ } ) . map ( function ( dat ) {
147+ dat . author = dat . maintainers
148+ delete dat . maintainers
149+ dat . date = dat . time
150+ delete dat . time
151+ return dat
152+ } ) . map ( function ( dat ) {
153+ // split keywords on whitespace or ,
154+ if ( typeof dat . keywords === "string" ) {
155+ dat . keywords = dat . keywords . split ( / [ , \s ] + / )
168156 }
169- if ( ! Array . isArray ( data . keywords ) ) data . keywords = [ ]
170- var l = [ data . name
171- , data . description || ""
172- , data . maintainers . join ( " " )
173- , data . time
174- , data . version || ""
175- , ( data . keywords || [ ] ) . join ( " " )
176- ]
177- l . forEach ( function ( s , i ) {
178- var len = s . length
179- longest [ i ] = Math . min ( maxLen [ i ] || Infinity
180- , Math . max ( longest [ i ] || 0 , len ) )
181- if ( len > longest [ i ] ) {
182- l . _undent = l . _undent || [ ]
183- l . _undent [ i ] = len - longest [ i ]
184- }
185- l [ i ] = ( '' + l [ i ] ) . replace ( / \s + / g, " " )
186- } )
187- return l
188- } ) . sort ( function ( a , b ) {
189- // a and b are "line" objects of [name, desc, maint, time, kw]
157+ if ( Array . isArray ( dat . keywords ) ) {
158+ dat . keywords = dat . keywords . join ( ' ' )
159+ }
160+
161+ // split author on whitespace or ,
162+ if ( typeof dat . author === "string" ) {
163+ dat . author = dat . author . split ( / [ , \s ] + / )
164+ }
165+ if ( Array . isArray ( dat . author ) ) {
166+ dat . author = dat . author . join ( ' ' )
167+ }
168+ return dat
169+ } )
170+
171+ lines . sort ( function ( a , b ) {
190172 var aa = a [ sortField ] . toLowerCase ( )
191173 , bb = b [ sortField ] . toLowerCase ( )
192174 return aa === bb ? 0
193- : aa < bb ? ( searchRev ? 1 : - 1 )
194- : ( searchRev ? - 1 : 1 )
195- } ) . map ( function ( line ) {
196- return line . map ( function ( s , i ) {
197- spaces = spaces || longest . map ( function ( n ) {
198- return new Array ( n + 2 ) . join ( " " )
199- } )
200- var len = s . length
201- if ( line . _undent && line . _undent [ i - 1 ] ) {
202- len += line . _undent [ i - 1 ] - 1
203- }
204- return s + spaces [ i ] . substr ( len )
205- } ) . join ( " " ) . substr ( 0 , cols ) . trim ( )
206- } ) . map ( function ( line ) {
207- // colorize!
208- args . forEach ( function ( arg , i ) {
209- line = addColorMarker ( line , arg , i )
210- } )
211- return colorize ( line ) . trim ( )
175+ : aa < bb ? - 1 : 1
212176 } )
213177
214- if ( lines . length === 0 ) {
215- return "No match found for " + ( args . map ( JSON . stringify ) . join ( " " ) )
216- }
178+ if ( searchRev ) lines . reverse ( )
217179
218- // build the heading padded to the longest in each field
219- return headings . map ( function ( h , i ) {
220- var space = Math . max ( 2 , 3 + ( longest [ i ] || 0 ) - h . length )
221- return h + ( new Array ( space ) . join ( " " ) )
222- } ) . join ( "" ) . substr ( 0 , cols ) . trim ( ) + "\n" + lines . join ( "\n" )
180+ var columns = npm . config . get ( "description" )
181+ ? [ "name" , "description" , "author" , "date" , "version" , "keywords" ]
182+ : [ "name" , "author" , "date" , "version" , "keywords" ]
183+
184+ var output = columnify ( lines , {
185+ include : columns
186+ , truncate : truncate
187+ , config : {
188+ name : { maxWidth : 40 , truncate : false , truncateMarker : '' }
189+ , description : { maxWidth : 60 }
190+ , author : { maxWidth : 20 }
191+ , date : { maxWidth : 11 }
192+ , version : { maxWidth : 11 }
193+ , keywords : { maxWidth : Infinity }
194+ }
195+ } )
196+ output = trimToMaxWidth ( output )
197+ output = highlightSearchTerms ( output , args )
223198
199+ return output
224200}
225201
226202var colors = [ 31 , 33 , 32 , 36 , 34 , 35 ]
227203 , cl = colors . length
204+
228205function addColorMarker ( str , arg , i ) {
229206 var m = i % cl + 1
230207 , markStart = String . fromCharCode ( m )
@@ -260,3 +237,29 @@ function colorize (line) {
260237 var uncolor = npm . color ? "\033[0m" : ""
261238 return line . split ( "\u0000" ) . join ( uncolor )
262239}
240+
241+ function getMaxWidth ( ) {
242+ try {
243+ var tty = require ( "tty" )
244+ , stdout = process . stdout
245+ , cols = ! tty . isatty ( stdout . fd ) ? Infinity
246+ : process . stdout . getWindowSize ( ) [ 0 ]
247+ cols = ( cols == 0 ) ? Infinity : cols
248+ } catch ( ex ) { cols = Infinity }
249+ return cols
250+ }
251+
252+ function trimToMaxWidth ( str ) {
253+ var maxWidth = getMaxWidth ( )
254+ return str . split ( '\n' ) . map ( function ( line ) {
255+ return line . slice ( 0 , maxWidth )
256+ } ) . join ( '\n' )
257+ }
258+
259+ function highlightSearchTerms ( str , terms ) {
260+ terms . forEach ( function ( arg , i ) {
261+ str = addColorMarker ( str , arg , i )
262+ } )
263+
264+ return colorize ( str ) . trim ( )
265+ }
0 commit comments