2

I need to confirm I have not created duplicate variables in a c file, while converting code from another language which is case insensitive.

For example, a file's content (below 2 lines) is:

  x = data1;
  data2 = Data1+ X;

Above text has x and X, data1 and Data1 and I want to know all such variables in the file.

5
  • I have got this from search as a solution but this again required me to manually go through sorted words and that too it is not effective in splitting words. cat <filename> | xargs -n1 | sed 's/[/ /g' | xargs -n1 | sort
    – DevBee
    Feb 7, 2017 at 16:01
  • Sorry, I'm a bit unclear on what you're looking for. You want to find all instances of data1 or Data1, but you don't want it in a search pattern? What do you want it in then?
    – Tumbler41
    Feb 7, 2017 at 16:03
  • 1
    @Tmbler41 I want to know such repeated words with case differing, and if case doesn't differ, I dont need them.
    – DevBee
    Feb 7, 2017 at 16:08
  • How would you differentiate between code and variables?
    – user41805
    Feb 7, 2017 at 16:09
  • There wont be such words in code, only variables might be created so, by mistake (or some other reasons). My language in context is C.
    – DevBee
    Feb 7, 2017 at 16:10

1 Answer 1

4

The following script provides the :Ambiguous command. It displays keywords (read :h 'iskeyword') that are the same but have different letter case in the location-list window.

The script is explained through its comments:

function! s:display_ambiguous() abort
  let buckets = {}

  " Split all text in the buffer by non-keywords.
  for word in split(join(getline(1, '$')), '\%(\k\@!.\)\+')
    " Words are collected into a bucket, keyed by the lowercased word.
    let key = tolower(word)
    if !has_key(buckets, key)
      let buckets[key] = []
    endif

    " Only add words that haven't been seen before.
    if index(buckets[key], word) == -1
      call add(buckets[key], word)
    endif
  endfor

  let ambiguous = []
  for [key, items] in items(buckets)
    " If a bucket has more than one item, add it to the results.
    if len(items) > 1
      call add(ambiguous, {
            \ 'text': join(items, ', '),
            \ 'bufnr': bufnr('%'),
            \ })
    endif
  endfor

  if !empty(ambiguous)
    " Set the contents of the location-list window.
    call setloclist(0, ambiguous, 'r')
    " Display the location-list window.
    lopen
  endif
endfunction


command! Ambiguous call s:display_ambiguous()
3
  • FWIW I agree with your last edit, but just to be clear, I make a lot of mistakes, and I also see other people doing a lot. Usually I don't try to fix them because they're not important / relevant to the question. But here, when I tried the code it didn't work at all because in Vim (could be wrong) it seems the list is ignored if you give a fourth argument. So I tried to fix the code so that it works as intended both in Vim and Neovim. Feb 8, 2017 at 18:22
  • By the way, I like your answers in general, they frequently make me learn something. Here for example, it made me learn how to simulate the pseudo-class \K inside the pattern \K\+ (sequence of non keyword characters). So far, I tried to do it like this: [^a-zA-Z_0-9\d192-\d255]\+. But your version is more readable, and takes into account the current value of 'isk': \%(\k\@!.\)\+ Feb 8, 2017 at 18:22
  • 1
    @user9433424 No sweat! It was actually my bad since I use Neovim and didn't realize the fourth argument was different from Vim's. Setting the quickfix title wasn't relevant to the question, so I thought it'd be better to just remove it and avoid confusion. Sorry if it seemed like a silent, passive-aggressive edit. SE doesn't make it easy to discuss revisions. I'm glad you get useful information out of my long-winded posts :-)
    – Tommy A
    Feb 8, 2017 at 20:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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