How to I have an activity diagram with a continue statement in PlantUML - uml

Given the following PlantUML code:
#startuml
start
repeat
:Task 1;
if (Condition 1) then (Yes)
:Task 2;
else (No)
:Continue Loop;
endif
if (Condition 2) then (Yes)
:Task 3;
else (No)
:Continue Loop;
endif
repeat while (More Data?) is (Yes) not (No)
end
#enduml
What I want is to have a loop continue where there is currently a task called Continue Loop. I can't see how this is possible.
Can someone please tell me what the syntax is for doing this?

What I want is to have a loop continue where there is currently a task called Continue Loop. I can't see how this is possible.
As Axel Kemper points out in his answer, there is no continue statement.
Like Axel, I refactored your if/then logic to nest the second condition inside the true result of the first condition. This makes it so that the continue instructions essentially fall through (false conditions) to the bottom of the loop. It's a solution to the example you gave, but it might not work for all cases of where you'd want to use a continue, like in Python or other languages:
#startuml
start
repeat
:Task 1;
if (Condition 1) then (Yes)
:Task 2;
if (Condition 2) then (Yes)
:Task 3;
else (No)
' :Continue Loop;
endif
else (No)
' :Continue Loop;
endif
repeat while (More Data?) is (Yes) not (No)
stop
#enduml

According to the PlantUML Reference Guide, no special continue command is available.
But there is a backward statement:
#startuml
start
repeat
:Task 1;
if (Condition 1) then (Yes)
:Task 2;
if (Condition 2) then (Yes)
:Task 3;
endif
endif
backward: Continue Loop;
repeat while (More Data?) is (Yes) not (No)
end
#enduml

Related

iostat and inputting from terminal

I understand the use of iostat, when we are inputting from terminal how do I make the status io<0 so that the program understands the end of input is reached?
For example in a simple code to find mean:
program mean
implicit none
real :: x
real :: gmean, amean, hmean
real :: summ,pro,invsum
integer :: i, valid
integer :: io, countt
countt=0
valid=0
summ=0
pro=1
invsum=0
do
read(*,*,iostat=io) x
if (io<0) exit
countt=countt+1
if (io>0) then
write(*,*) 'error in input..try again !!!'
else
write(*,*) 'Input data #.',countt,':',x
if (x<=0) then
write(*,*) 'input <=0..ignored !!'
else
valid = valid + 1
summ = summ + x
pro = pro*x
invsum = invsum + (1.0/x)
end if
end if
end do
if (valid>0) then
amean=summ / valid
gmean = pro**(1.0/valid)
hmean=valid / invsum
write(*,*) 'number of valid items --->',valid
write(*,*) 'arithmetic mean --> ',amean
write(*,*) 'geometric mean --> ',gmean
write(*,*) 'harmonic mean --> ',hmean
else
write(*,*) 'no valid inputs !!'
end if
end program mean
When I execute the code everything works fine except it keeps on asking for inputs. I do not understand how to make io<0.
On Unix systems such as Linux and MAC OS, you can use Ctrl-d to signal the end of the file.
On Windows, use Ctrl-z (from here).
This Wikipedia article compares further command line shortcuts on the various operating systems.
I like to be nice to the user (even if its just me..)
character*80 input
real val
integer stat
input=''
do while(input.ne.'e')
write(*,'(a)',advance='no')'enter val [e to end]: '
read(*,'(a)',iostat=stat)input !iostat here to catch ^d and such
if(stat.ne.0)input='e'
if(input.ne.'e')then
read(input,*,iostat=stat)val !check iostat here
!in case user entered some
if(stat.ne.0)then !other non-number
write(*,*)val
else
write(*,*)'expected a number'
endif
endif
enddo
end

Wait loop on two conditions using VBA

I need the macro to loop if one of the criteria is not met. Working with some basic scraping. I need this to loop until ready before I start gathering data.
If ie.document.getElementsByClassName("clicks").Length < 1 Or ie.document.getElementsByClassName("feedback").Length < 1 Then
Do: Loop
End If
I think it would look like this :
Do While ie.document.getElementsByClassName("clicks").Length >= 1 And ie.document.getElementsByClassName("feedback").Length >= 1
'''code
Loop
Your loop does not check with each iteration, only once and if it is not ready then it will enter an infinite loop. You need a solution that checks each time the loop iterates.
Do
If ie.document.getElementsByClassName("clicks").Length < 1 Or ie.document.getElementsByClassName("feedback").Length < 1 Then
DoEvents 'free the processor to work on other things
Else
Exit Do
End If
Loop
This will check each time the loop iterates rather than just once.

How can I create useful fold expressions if they can't have any side effects?

I'm trying to make a very simple fold expression for Ruby:
let s:fold_indent = []
function! RubyFoldLevel(lnum)
let l:prevline = getline(a:lnum - 1)
let l:curline = getline(a:lnum)
let l:nextline = getline(a:lnum + 1)
" if l:curline=~'^\s*\(module\)\|\(class\)\|\(def\)\s'
if l:curline=~'^\s*def\s'
add(s:fold_indent, indent(a:lnum))
echo s:fold_indent
return 'a1'
elseif l:curline=~'^\s*end\s*$'
\ && len(s:fold_indent) > 0
\ && indent(a:lnum) == s:fold_indent[-1]
unlet s:fold_indent[-1]
echo s:fold_indent
return 's1'
end
return '='
endfunction
My plan is to add to the fold level ("a1") whenever I stumble upon a def, then subtract from the fold level ("s1") when I find the end at the same level of indentation. Here I'm attempting to do this by saving the indentation in a stack and only ending a fold when the topmost item in the stack matches the indentation level of the current line.
This doesn't work because the fold expression can't actually edit the contents of s:fold_indent (notice the echo s:fold_indent. It prints [] every time.) I suppose this makes sense since it's useful to be able to use the expression on any line regardless of order, however I can't work out how to write a useful fold expression without it.
Is it possible to fulfill my plan without maintaining a stack outside of the function?
Side effects in a fold expression only refer to changing text or switching windows (called textlock in Vim). The problem is rather that you've missed a :call in front of the add():
call add(s:fold_indent, indent(a:lnum))
(This becomes obvious when you manually invoke the function.)
Nonetheless, using shared state is problematic, because you have no control where (and in which order) Vim evaluates the fold expression. For Ruby folding, I'd rather rely on the syntax highlighting (which already defines regions for def ... end) to provide the folding information (and the syntax/ruby.vim that ships with Vim already does).
Alright, I think I figured it out. My function now indents any time module, class or def is encountered. Any time end is encountered, the function iterates backwards over previous lines until a module, class or def is found at the same indentation level as the end, and if one is found it subtracts the fold level.
After a few minutes of testing and a few lines of code to handle special cases (0 or 1 line folds) it appears to work perfectly:
function! RubyFoldLevel(lnum)
let l:prevline = getline(a:lnum - 1)
let l:curline = getline(a:lnum)
let l:nextline = getline(a:lnum + 1)
let l:fold_starter = '^\s*\(\(module\)\|\(class\)\|\(def\)\)\s'
let l:fold_ender = '^\s*end\s*$'
" Prevent 1-line folds.
if indent(a:lnum - 1) == indent(a:lnum + 1)
\ && l:prevline =~ l:fold_starter
\ && l:nextline =~ l:fold_ender
return "="
end
if l:prevline=~l:fold_starter
\ && !(l:curline =~ l:fold_ender && indent(a:lnum - 1) == indent(a:lnum))
return 'a1'
end
if l:nextline=~l:fold_ender
\ && !(l:curline =~ l:fold_starter && indent(a:lnum) == indent(a:lnum + 1))
let l:cursor = a:lnum + 1
while 1
let l:cursor = prevnonblank(l:cursor - 1)
" Fold starter found at this indentation level.
if indent(l:cursor) == indent(a:lnum + 1)
\ && getline(l:cursor)=~l:fold_starter
return 's1'
end
" No fold starter found at this indentation level.
if indent(l:cursor) < indent(a:lnum + 1)
break
end
endwhile
end
return '='
endfunction
setlocal foldmethod=expr
setlocal foldexpr=RubyFoldLevel(v:lnum)
Needless to say, this fold expression will only work on source files with "correct" indentation.

Fold up to the fold start, instead of the indent start

I use foldmethod=indent and when I fold code like this:
def cake():
#cake!
print( "cake" )
print( "for" )
print( "you" )
I see
def cake():
#cake!
print( "cake" ) +++ 3 lines folded
but I want to see
def cake(): +++ 5 lines folded
Is there a way to do fold up to the first line (def cake():) like this?
Chapters 48 and 49 of Learn Vimscript the Hard Way talk about how to do that, using foldmethod=expr instead of indent. Basically you need to make a custom ftplugin and put a folding script in it; the script contains functions used to determine what fold level different lines should have.
As luck would have it, the example code given in those two chapters is for the Potion language which, like Python, is whitespace-sensitive, so it should be pretty easy to adapt it to Python. Since Vim already comes with a Python ftplugin, I think you can put the folding script described on the site into .vim/after/ftplugin/python instead of .vim/ftplugin/potion.
I solved this using this tutorial.
This is the finished bunch of functions:
fu! Indent_level(lnum)
return indent(a:lnum) / &shiftwidth
endfunction
fu! Next_non_blank_line(lnum)
let numlines = line('$')
let current = a:lnum + 1
while current <= numlines
if getline(current) =~? '\v\S'
return current
endif
let current += 1
endwhile
return -2
endfunction
fu! Custom_fold_expr(lnum)
if getline(a:lnum) =~? '\v^\s*$'
return '-1'
endif
let this_indent = Indent_level(a:lnum)
let next_indent = Indent_level(Next_non_blank_line(a:lnum))
if next_indent == this_indent
return this_indent
elseif next_indent < this_indent
return this_indent
elseif next_indent > this_indent
return '>' . next_indent
endif
endf
set foldexpr=Custom_fold_expr(v:lnum)
foldmethod=expr
Please don't edit the indentation of the "end" markers on this post, it looks gorgeous after you put this in your vimrc.

Vim: How to number paragraphs automatically and how to refer to this numbering?

Let us say I have the following three paragraphs of text (separated
from each other by empty lines—number 3 and 7, here):
This is my first paragraph line 1
This is my first paragraph line 2
This is my second paragraph line 4
This is my second paragraph line 5
This is my second paragraph line 6
This is my third paragraph line 8
This is my third paragraph line 9
Question 1: How can I number these paragraphs automatically,
to obtain this result:
1 This is my first paragraph line 1
This is my first paragraph line 2
2 This is my second paragraph line 4
This is my second paragraph line 5
This is my second paragraph line 6
3 This is my third paragraph line 8
This is my third paragraph line 9
(I succeeded to do this, but only via a clumsy macro.)
Question 2: Is it possible to refer to these paragraphs? For
instance, is it possible to index a text file as answered (by Prince
Goulash and Herbert Sitz) in the earlier question, but this time
with the paragraph numbers and not the line numbers?
Thanks in advance.
Here's one way to do the ref numbers, with a pair of functions:
function! MakeRefMarkers()
" Remove spaces from empty lines:
%s/^ \+$//
" Mark all spots for ref number:
%s/^\_$\_.\zs\(\s\|\S\)/_parref_/
" Initialize ref val:
let s:i = 0
" Replace with ref nums:
%s/^_parref_/\=GetRef()/
endfunction
function! GetRef()
let s:i += 1
return s:i . '. '
endfunction
Then just do it by calling MakeRefMarkers(). It doesn't remove existing ref numbers if they're there, that would require another step. And it doesn't catch first paragraph if it's first line in file (i.e, without preceding blank line). But it does handle situations where there's more than one blank line between paragraphs.
Question One
Here is a function to enumerate paragraphs. Simply do :call EnumeratePara() anywhere in your file. The variable indent can be adjusted as you wish. Let me know if anything needs correcting or explaining.
function! EnumeratePara()
let indent = 5
let lnum = 1
let para = 1
let next_is_new_para = 1
while lnum <= line("$")
let this = getline(lnum)
if this =~ "^ *$"
let next_is_new_para=1
elseif next_is_new_para == 1 && this !~ "^ *$"
call cursor(lnum, 1)
sil exe "normal i" . para . repeat(" ", indent-len(para))
let para+=1
let next_is_new_para = 0
else
call cursor(lnum, 1)
sil exe "normal i" . repeat(" ", indent)
endif
let lnum += 1
endwhile
endfunction
Question Two
This isn't a very elegant approach, but it seems to work. First of all, here's a function that maps each line in the file to a paragraph number:
function! MapLinesToParagraphs()
let lnum = 1
let para_lines = []
let next_is_new_para = 1
let current_para = 0
while lnum <= line("$")
let this = getline(lnum)
if this =~ "^ *$"
let next_is_new_para = 1
elseif next_is_new_para == 1
let current_para += 1
let next_is_new_para = 0
endif
call add(para_lines, current_para)
let lnum += 1
endwhile
return para_lines
endfunction
So that para_lines[i] will give the paragraph of line i.
Now we can use the existing IndexByWord() function, and use MapLinesToParagraph() to convert the line numbers into paragraph numbers before we return them:
function! IndexByParagraph(wordlist)
let temp_dict = {}
let para_lines = MapLinesToParagraphs()
for word in a:wordlist
redir => result
sil! exe ':g/' . word . '/#'
redir END
let tmp_list = split(strtrans(result), "\\^\# *")
let res_list = []
call map(tmp_list, 'add(res_list, str2nr(matchstr(v:val, "^[0-9]*")))')
call map(res_list, 'para_lines[v:val]')
let temp_dict[word] = res_list
endfor
let result_list = []
for key in sort(keys(temp_dict))
call add(result_list, key . ' : ' . string(temp_dict[key])[1:-2])
endfor
return join(result_list, "\n")
endfunction
I have not tested these functions very thoroughly, but they seem to work okay, at least in your example text. Let me know how you get on!
Both problems could be solved much easier than it is suggested
by the other two answers.
1. In order to solve the first problem of numbering paragraphs,
the following two steps are ample.
Indent the paragraphs (using tabs, here):
:v/^\s*$/s/^/\t/
Insert paragraph numbering (see also my answer to
the question on substitution with counter):
:let n=[0] | %s/^\s*\n\zs\ze\s*\S\|\%1l/\=map(n,'v:val+1')
2. The second problem of creating index requires some scripting in
order to be solved by Vim means only. Below is the listing of a small
function, WordParIndex() that is supposed to be run after paragraphs
are numbered according to the first problem's description.
function! WordParIndex()
let [p, fq] = [0, {}]
let [i, n] = [1, line('$')]
while i <= n
let l = getline(i)
if l !~ '^\s*$'
let [p; ws] = ([p] + split(l, '\s\+'))[l=~'^\S':]
for w in ws
let t = get(fq, w, [p])
let fq[w] = t[-1] != p ? t + [p] : t
endfor
endif
let i += 1
endwhile
return fq
endfunction
The return value of the WordParIndex() function is the target index
dictionary. To append its text representation at the end of a buffer,
run
:call map(WordParIndex(), 'append(line("$"),v:key.": ".join(v:val,","))')
My approach would be macro based:
Yank the number "0" somehow and move to the start of the first paragraph.
Record a macro to
Indent the paragraph with >}
Paste the stored number at the correct position p
Increment the number by one with <ctrl>-a
Yank the pasted number with yiw
Move to the next paragraph with }l or /^\S
Execute the macro as many times as needed to reach the end of the document.
The method of pasting a number, incrementing it, and then reyanking it inside a macro is quite a useful technique that comes in handy whenever you need to number things. And it's simple enough to just do it in a throw-away fashion. I mainly use it for carpet logging, but it has other uses as your question demonstrates.

Resources