There is no goto in vimscript [1]. Like most languages that lack goto, you'll need to handle this using a variable:
let breaking = 0
for i in range(3)
for j in range(5)
echo i j
if i == 1 && j == 2
breaking = 1
break
endif
endfor
if breaking
break
endif
endfor
You can also use j outside of the loop, although this is a bit brittle to any code changes later.
for i in range(3)
for j in range(5)
echo i j
if i == 1 && j == 2
break
endif
endfor
if i == 1 && j == 2
break
endif
endfor
Another way to handle this is with a double loop
let Zip = {a,b -> a->mapnew({_,x -> b->mapnew({_,y -> [x, y]})})->flatten(1)}
for [i, j] in Zip(range(3), range(5))
echo i j
if i == 1 && j == 2
break
endif
endfor
Zip is quite cryptic, but just demonstrating the double for concept.
Finally, you can restructure your program to avoid the nested loop,
function! DoWork(i)
for j in range(5)
echo a:i j
if a:i == 1 && j == 2
return 1
endif
endfor
return 0
endfunction
for i in range(3)
if DoWork(i)
break
endif
endfor
or in vim9script,
vim9script
for i in range(3)
if () => {
for j in range(5)
echo i j
if i == 1 && j == 1
return 1
endif
endfor
return 0
}()
break
endif
endfor
[1] of course, there is a goto in vim script but it definitely doesn't do what you want!