1

We can read some information about the current buffer, by hitting g C-g; for example:

Col 3 of 2; Line 28 of 106; Word 144 of 474; Byte 916 of 3396

And we can capture the same information in a dictionary using the wordcount() function:

:echo wordcount()

{'chars': 3396, 'cursor_chars': 916, 'words': 474, 'cursor_words': 144, 'bytes': 3396, 'cursor_bytes': 916}

In both cases, we read/get the number of characters, words and bytes, as well as the position of the cursor expressed with these 3 units. It allows to get an idea of the amount of text.

But to get an idea of the amount of code in a file, where there may be a lot of comments and/or blank lines, could we also read/get the number of the latter as well as the number of lines of code?

2

Here's a way of getting the information:

com! -range=% -nargs=? -complete=file CLOC call s:cloc(<line1>,<line2>,<q-args>)

nno <silent> g<C-l> :CLOC<CR>
xno <silent> g<C-l> :CLOC<CR>

fu! s:cloc(lnum1,lnum2,path) abort

    if !empty(a:path)
        let to_scan = a:path
    else
        let file    = tempname()
        let to_scan = file.'.'.&ft
        let lines   = getline(a:lnum1, a:lnum2)
        call writefile(lines, to_scan)
    endif

    let cloc_output = matchstr(system('cloc '.to_scan), 'http.\{-}\n\zs.*\ze\n')

    if empty(a:path)
        call delete(to_scan)
    endif

    let to_display = cloc_output

    let cloc_output = map(filter(split(cloc_output, "\n"), 'v:val =~# ''\d\+'''),
                     \ 'split(v:val, ''\s\{2,}\ze\d'')')

    let g:cloc_results = {}
    let keys           = ['files', 'blank', 'comment', 'code']

    for values_on_line in cloc_output
        let i    = 0
        let dict = {}

        for value in values_on_line[1:]
            let dict[keys[i]] = eval(value)
            let i += 1
        endfor

        let g:cloc_results[values_on_line[0]] = dict
    endfor

    echo to_display
endfu

It relies on the cloc shell command, which, on debian based distributions, can be installed with:

sudo apt-get install cloc

It can also be downloaded from github.


It installs normal and visual mode mappings, both using the key sequence g C-l (l for lines).

The normal mapping allows to read the number of lines of code, comments and blank lines in the current buffer. The visual mapping allows to get the same info for the visual selection.

It also installs the Ex command :CLOC, which accepts a range (matching the whole buffer by default), and a path to a file or a folder.

When passed a path, :CLOC should scan all the files under the latter.

Both the mappings and the Ex command should populate the global variable g:cloc_results with a dictionary. Each key of this dictionary should be a programming language (except one named SUM:).
Each value should be another dictionary. This sub-dictionary should contain the 4 following keys:

files      " number of files under the path whose language is the name of the dictionary
code       "           total lines of code for this language
comment    "           total comment lines "
blank      "           total blank lines   "

enter image description here

Inside a script, where the only thing desired is the global variable (no message) :CLOC could be executed silently:

silent CLOC /path

Then, one could access the data for a given language, let's say python, like this:

let yourvar = g:cloc_results.Python

It should give something like:

{'comment': 2213, 'files': 93, 'code': 10970, 'blank': 2630}

And if the language contains a space, like Bourne Shell, you could use this other syntax, where the space is protected in a string:

let yourvar = g:cloc_results['Bourne Shell']

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.