Re: failing to read xml

2020-01-08 Thread marks
I found that if I don't go into child nodes then it doesn't assert: but then it 
doesn't go through the XML file either! Here's a modified `write` that still 
asserts: 


proc write(file: File, node: XmlNode, indent: int) =
  if indent > 0:
file.write(spaces(indent))
  file.write(&"<{node.tag}")
  let attrs = node.attrs()
  if attrs != nil:
for (key, value) in attrs.pairs():
  file.write(&" {key}=\"{value}\"")
  file.write(">")
  if node.kind != xnElement and node.text != "":
file.write(node.text)
  if len(node) > 0:
for child in node:
  write(file, child, indent + INDENT)
  file.write(&"\n")


Run

I tried commenting out the attrs code and the node.text code but that didn't 
help.

SOLVED: The problem was with the signature. Even though I don't (knowingly) 
modify any nodes, changing the signature's `node: XmlNode` to `node: var 
XmlNode` cured the assertion error.


Re: failing to read xml

2020-01-08 Thread marks
I modified the `write` proc as suggested but it doesn't help:


if node.kind in {xnText, xnCData, xnEntity, xnComment} and
  node.text != "":
file.write(node.text)


Run

Assert: 


fatal.nim(39)sysFatal
Error: unhandled exception: xmltree.nim(213, 10) `n.k == xnElement`  
[AssertionError]


Run

I also tried:


if node.kind != xnElement and node.text != "":
file.write(node.text)


Run

And that also asserted with the same message.

And just to be sure I then commented out the `if` statement so that I _never_ 
use `node.text`; and it still gives exactly the same assertion.


failing to read xml

2020-01-08 Thread marks
I'm trying to learn nim's `xmlparser` and `xmltree` modules.

To do this I'm writing a program that will (eventually) pretty-print XML.

But unfortunately, it asserts on every XML file I've tried to run it with. The 
code and the smallest possible XML file I could make that asserts and the 
assert itself are as follows:


# xml2xml.nim
{.experimental: "codeReordering".}

import os
import strformat
import strtabs
import strutils
import xmlparser
import xmltree

const INDENT = 4

main()

proc main() =
  let args = commandLineParams()
  if len(args) == 0 or args[0] in ["/?", "-h", "--help"]:
let appname = lastPathPart(getAppFilename())
quit(&"usage: {appname} file.xml [file2.xml ...]")
  for arg in args:
pretty(arg)

proc pretty(infilename: string) =
  let i = infilename.rfind('.')
  let outfilename = infilename[0 ..< i] & "#.xml"
  var errors = newSeq[string]()
  let root = loadXml(infilename, errors)
  if len(errors) > 0:
for error in errors:
  echo(&"Error: {error}")
  try:
var file = open(outfilename, fmWrite)
defer: file.close()
file.write(xmlHeader)
write(file, root, 0)
  except IOError as err:
echo(&"Failed to write to \"{outfilename}\": {err.msg}")

proc write(file: File, node: XmlNode, indent: int) =
  if indent > 0:
file.write(spaces(indent))
  file.write(&"<{node.tag}")
  let attrs = node.attrs()
  if attrs != nil:
for (key, value) in attrs.pairs():
  file.write(&" {key}=\"{value}\"")
  file.write(">")
  if node.text != "":
file.write(node.text)
  for child in node:
write(file, child, indent + INDENT)
  file.write(&"\n")


Run

The simpletest XML file I could make (`meta.xml`):







Run

The runtime assertion error: 


/home/mark/app/nim/xml2xml/xml2xml.nim(16) xml2xml
/home/mark/app/nim/xml2xml/xml2xml.nim(24) main
/home/mark/app/nim/xml2xml/xml2xml.nim(38) pretty
/home/mark/app/nim/xml2xml/xml2xml.nim(51) write
/home/mark/opt/nim/lib/pure/xmltree.nim(176) text
/home/mark/opt/nim/lib/system/assertions.nim(27) failedAssertImpl
/home/mark/opt/nim/lib/system/assertions.nim(20) raiseAssert
/home/mark/opt/nim/lib/system/fatal.nim(39) sysFatal
Error: unhandled exception: /home/mark/opt/nim/lib/pure/xmltree.nim(176, 
10) `n.k in {xnText, xnComment, xnCData, xnEntity}`  [AssertionError]


Run

The problem could, of course, be with my own code: maybe I don't understand how 
to use `xmltree` and `XmlNode`'s properly yet.


Re: A path commonPrefix function

2020-01-06 Thread marks
Using your `for j in 1 .. paths.high()` is _much_ faster than my `for s in 
paths[1 .. ^1]`, but for me my `foldl` is much faster than your `maxLen`. (My 
test data isn't great though, a dozen calls, eleven with common prefixes, 
repeated 100K times.)

Maybe a common prefix algorithm should be in the std. lib., perhaps with one 
version that is "raw" and another which does prefixes only at a given separator?


Re: A path commonPrefix function

2020-01-05 Thread marks
I tried the binary search approach but it was still much slower than my best 
version on my test data.

For reference, here's what I tried: 


proc commonPrefix*(paths: openArray[string], sep = "/"): string =
  if len(paths) < 1:
return ""
  let first = paths[0]
  if len(first) < 2:
return first
  var lo = 0
  var hi = foldl(paths.mapIt(len(it)), min(a, b)) - 1 # min len
  while lo <= hi:
let mid = lo + (hi - lo) div 2
var ok = true
block loop:
  for s in paths[1 .. ^1]:
for i in lo .. mid:
  if s[i] != first[i]:
ok = false
break loop
if ok:
  result.add(first[lo .. mid])
  lo = mid + 1
else:
  hi = mid - 1


Run


Re: A path commonPrefix function

2020-01-04 Thread marks
This is the fastest and best so far: 


proc commonPrefix*(paths: openArray[string], sep = "/"): string =
  if len(paths) == 0:
return ""
  let first = paths[0]
  var index = -1
  block loop:
for i in 0 ..< len(first):
  for j in 1 .. paths.high():
let path = paths[j]
if i < len(path) and first[i] != path[i]:
  break loop
  index = i
  if index == -1:
return ""
  else:
return first[0 .. first.rfind(sep, 0, index)]


Run


Re: A path commonPrefix function

2020-01-04 Thread marks
Thanks for that. I discovered that my new version is 4x faster than the 
original..


Re: A path commonPrefix function

2020-01-04 Thread marks
This version walks forward char by char. Is there a nim equivalent to Python's 
`timeit` module for timing snippets? 


proc commonPrefix*(paths: openArray[string], sep = "/"): string =
  if len(paths) == 0:
return ""
  result = paths[0]
  var index = 0
  var ok = false
  for path in paths[1 .. ^1]:
while index < len(path) and index < len(result) and
result[index] == path[index]:
  inc index
  ok = true
  result = if not ok:
  ""
  else:
result[0 .. result.rfind(sep, 0, index)]


Run


A path commonPrefix function

2020-01-03 Thread marks
I have the following `commonPrefix()` function (for whole paths) which works 
fine on Linux (and Windows), but wondering if it could be shorter and/or more 
efficient?


proc commonPrefix*(paths: openArray[string], sep = "/"): string =
  if len(paths) == 0:
return ""
  result = paths[0]
  for path in paths[1 .. ^1]:
while not path.startsWith(result) and len(result) > 0:
  result = result[0 .. ^2]
  result = result[0 .. result.rfind(sep)]


Run

Tests: 


test "commonPrefix":
  check(commonPrefix(["/tmp/test1", "/tmp/data.dat"]) == "/tmp/")
  check(commonPrefix(["/home/mark/test1", "/tmp/data.dat"]) == "/")
  check(commonPrefix(["/home/mark/test1", "local/data.dat"]) == "")


Run


Re: can use zip library on Linux but not on Windows

2019-12-29 Thread marks
That link is helpful, thank you. For anyone else who hits this, I added these 
two lines after the imports: 


when defined(windows):
  {.passl: "-lz".}


Run

It now compiles & runs & lists zip contents on Windows and Linux. And the 
executable doesn't seem to depend on any separate shared libs, so is 
conveniently stand-alone. 


can use zip library on Linux but not on Windows

2019-12-29 Thread marks
On both Linux and Windows `nimble list -i`'s output includes: `zip [0.2.1]`.

On Linux the program listed below compiles & runs & lists a zip file.

On Windows I just get error messages (shown after the program).

nzip.nim 


{.experimental: "codeReordering".}

import os
import strformat
import strutils
import unicode
import zip/zipfiles

type Action = enum actCreate, actExtract, actList

main()

proc main() =
  let (action, infilename, files) = readCommandLine() # May not return
  case action
  of actCreate: echo("TODO create")
  of actExtract: echo("TODO extract")
  of actList: listFiles(infilename)

proc readCommandLine(): (Action, string, seq[string]) =
  var action = actList
  var infilename = ""
  var files = newSeq[string]()
  let args = commandLineParams()
  if len(args) == 0 or args[0] == "-h" or args[0] == "--help":
  echo(&"usage: {lastPathPart(getAppFilename())} " &
   "[-c|--create] " &
   "[-e|-x|--extract] " &
   "[-l|-t|--list] file.zip \n" &
   "(Hyphen prefixes are not required.)")
  quit()
  for arg in args:
case arg
of "c", "-c", "--create", "create": action = actCreate
of "l", "t", "-l", "-t", "--list", "list": action = actList
of "e", "x", "-e", "-x", "--extract", "extract": action = actExtract
else:
  if infilename == "" and arg.toLower().endsWith(".zip"):
infilename = arg
  else:
files.add(arg)
  (action, infilename, files)

proc listFiles(infilename: string) =
  var archive: ZipArchive
  if open(archive, infilename):
defer: archive.close()
for name in archive.walkFiles():
  echo(name)
  else:
echo(&"failed to open \"{infilename}\"")


Run

Errors on Windows: 


Hint: used config file 'C:\bin\nim\config\nim.cfg' [Conf]
R:\nim\nzip\nzip.nim(18, 28) Hint: 'files' is declared but not used 
[XDeclaredButNotUsed]
Hint:  [Link]
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x2c3): 
undefined reference to `crc32'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x33e): 
undefined reference to `deflateInit2_'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x366): 
undefined reference to `deflate'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x416): 
undefined reference to `crc32'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x426): 
undefined reference to `deflateEnd'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x4c1): 
undefined reference to `deflateEnd'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x16f4): 
undefined reference to `zError'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x371f): 
undefined reference to `zError'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x37c3): 
undefined reference to `inflateEnd'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x38a4): 
undefined reference to `crc32'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x38de): 
undefined reference to `crc32'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x39c5): 
undefined reference to `zError'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x3fc3): 
undefined reference to `crc32'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x406e): 
undefined reference to `inflateEnd'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x4250): 
undefined reference to `inflateInit2_'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x4270): 
undefined reference to `inflateEnd'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x431a): 
undefined reference to `inflateEnd'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x63c6): 
undefined reference to `inflate'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x6426): 
undefined reference to `crc32'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x6606): 
undefined reference to `crc32'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x670d): 
undefined reference to `inflateEnd'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x680f): 
undefined reference to `inflateEnd'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x6956): 
undefined reference to `inflate'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x69ad): 
undefined reference to `crc32'
C:\Users\mark\nimcache\nzip_r\libzip_all.c.o:libzip_all.c:(.text+0x6b35): 
undefined reference to `crc32'

File and directory structure for a hybrid project

2019-12-25 Thread marks
I have a project that consists of a library (that will be split over several 
files but will have a single file as its entry point) and an executable that 
uses the library but which doesn't share its name. At the moment I have this 
layout: 


src/myexe.nim
src/mypkg/mypkg.nim
src/mypkg/support1.nim


Run

but when I run `nimble test` I get a warning about the structure.

So, what should the structure be?


An overview of nimble.packages

2019-12-23 Thread marks
I wanted to get an overview of the nimble packages but there isn't a browse 
function, so I wrote the nim program below. To use it you need to download 
`packages.json` from [nimble.packages](https://github.com/nim-lang/packages/). 


{.experimental: "codeReordering".}

# TODO download the JSON file if mtime is older than today

import algorithm
import json
import os
import sequtils
import strformat
import strutils except escape
import sugar
import unicode
import xmltree

const Outfile = "nimble-packages.html"

type
  Entry = object
name: string
url: string
tags: seq[string]
description: string
license: string
web: string

main()

proc main() =
  let filename = getFilename() # May not return
  let entries = entryItems(filename)
  writeHtmlTable(entries)

proc getFilename(): string =
  let args = commandLineParams()
  if len(args) == 0 or args[0] == "-h" or args[0] == "--help":
echo("usage: ", lastPathPart(getAppFilename()),
 " /path/to/nimble.packages.json")
quit()
  args[0]

proc entryItems(filename: string): seq[Entry] =
  for item in parseJson(readFile(filename)):
var entry: Entry
try:
  entry = to(item, Entry)
except KeyError:
  for tag in ["name", "url", "description", "license", "web"]:
try:
  let node = item[tag]
  let text = node.getStr()
  case tag
  of "name": entry.name = text
  of "url": entry.url = text
  of "description": entry.description = text
  of "license": entry.license = text
  of "web": entry.web = text
except KeyError:
  discard # ignore missing for now
  try:
let node = item["tags"]
if node.kind == JArray:
  var tags = newSeq[string]()
  for element in node.getElems():
tags.add(element.getStr())
  entry.tags = tags
  except KeyError:
discard # no tags
if entry.name == "":
  continue
entry.tags = sorted(entry.tags.mapIt(it.toLower()))
result.add(entry)
if entry.url == "":
  entry.url = entry.web
  result.sort((a, b) => cmpIgnoreCase(a.name, b.name))

proc writeHtmlTable(entries: seq[Entry]) =
  var file = open(Outfile, fmWrite)
  defer: close(file)
  file.write("\n")
  file.write("Name/LinkDescriptionTags" &
 "License\n")
  for entry in entries:
let name = &"{escape(entry.name)}"
let description = escape(entry.description)
let tags = escape(join(entry.tags, ", "))
let license = escape(entry.license)
file.write(&"{name}{description}" &
   &"{tags}{license}\n")
  file.write("\n")
  file.write(&"{len(entries)} packages.\n")


Run


Re: How to make a new lib work for nimble.packages?

2019-12-20 Thread marks
I normally use mercurial so now have both in that directory. I added a tag and 
did `git push origin --tags` so hopefully that helped.


How to make a new lib work for nimble.packages?

2019-12-20 Thread marks
I created a new package using `nimble init` and once it was ready `nimble 
publish` and put it on github: [diff](https://github.com/mark-summerfield/diff) 
but on the [nimble directory](https://nimble.directory/pkg/diff) it is listed 
as "no version" and "install test failing", and the link to "Hosted docs" leads 
to an empty page.

How do I fix these things?


Re: diff lib

2019-12-19 Thread marks
I think we're doing two different kinds of diff. My library takes sequences `a` 
and `b` and returns a sequence of "spans" (i.e., insert/delete/replace a from 
to, b from to) that if applied to `a` would transform it into `b`. This is 
explained in the Python [difflib 
docs](https://docs.python.org/3/library/difflib.html).


diff lib

2019-12-19 Thread marks
I've ported Python's difflib's sequence matcher to pure Nim: 
[diff](https://github.com/mark-summerfield/diff).

It can be used to see the differences between any two sequences of items that 
support `==` and `hash()` (string, char, or any custom item type with the 
necessary support). 


Re: Is it possible to browse the nimble.directory?

2019-12-19 Thread marks
Search is great if you know what you're looking for. But it is useless for 
getting an overview of what's available. And an overview of the third-party 
libraries is what I want when starting with a new language.


Re: how to create a generic type with constraints?

2019-12-18 Thread marks
Thanks. I think I'll do without concepts for now.


how to create a generic type with constraints?

2019-12-18 Thread marks
I'm trying to port Python's difflib's sequence matcher to nim. I want to be 
able to compare any two sequences of the same types, not just strings.

I have this type: 


type
  Diff[T] = object
a: seq[T]
b: seq[T]
b2j: Table[T, seq[int]]


Run

How can I say that type `T` must support `==` and `hash()`?


Re: A pure nim GUI game for Linux & Windows

2019-12-17 Thread marks
`shuffle()` is in-place but it did save me one line: 


var colors = gameColors # gameColors is a const seq[Color]
shuffle(colors)
colors = colors[0 ..< game.maxColors]


Run

It is true that NiGui uses Gtk on Linux, but Gtk is pretty well always on 
desktop/laptop systems even KDE ones, since there're bound to be apps that 
depend on it.

Nim could certainly do with a really good book -- I'd certainly like to read 
one.

(I've dipped into Nim in Action, but I felt it was too close to the docs, the 
main examples didn't appeal to me, and it isn't Nim 1.0.)

As for writing a Nim book: (1) I'd need to have done a lot more Nim programming 
-- which I'm in the process of doing; (2) I'd need to have at least one core 
dev willing to read and give feedback on all the examples _and_ on the text -- 
over a 12-18 month period; (3) I'd need to interest my -- or another -- 
publisher; (4) I'd need to feel motivated to spend at least a year working on a 
book that's likely to sell only a few thousand copies and so be a labor of love 
rather than economically viable. So I'm hoping someone else does it:-)


Re: A pure nim GUI game for Linux & Windows

2019-12-17 Thread marks
I can't find outplace (at least not in 1.0.4 or 'latest' on the Nim 
playground). However, I'll have another go with shuffle which I already use 
elsewhere.

I'm sure there are other Nim libs that support NiGui's missing features -- but 
don't all of them depend on SDL or OpenGL or other third party libs?

As for github, I have an a/c there to contribute, but I don't put my own 
projects there. My gravitate packages include the full source.


A pure nim GUI game for Linux & Windows

2019-12-16 Thread marks
As part of the process of learning Nim, I've ported my game _Gravitate_ (a 
variation of TileFall or the SameGame), to Nim.

I used the [NiGui](https://github.com/trustable-code/NiGui) library, so no 
third party `.so`'s or `.dll`'s are needed.

Although I've tried to make the most of Nim and to be as idiomatic as possible, 
I'm sure there's room for improvement. So I hope that some Nim experts will 
review the source and give me feedback -- or just edited `.nim` files -- to 
help me improve my code. (For example, in the `game.nim` file's `start()` 
function it takes me 4 lines to choose 4 unique random colors from a sequence 
of 17; surely it can be done in less code?)

There are two archives available from the game's [home 
page](http://www.qtrac.eu/gravitate.html). The direct downloads (both including 
64-bit executables and full source code <1 KLOC) are 
[Windows](http://www.qtrac.eu/gravitate-1.0.0.zip) and 
[Linux](http://www.qtrac.eu/gravitate-1.0.0.tar.gz).

Things I couldn't do because either I can't figure out how or because NiGui 
doesn't support them:

  * Underline keyboard accelerator letters, e.g., the New game button shows 
"New", but I'd like the 'N' underlined.
  * Include icons in the buttons and to set the executable's icon all in code 
(e.g., by reading base64-encoded text from a file at compile time).
  * Show tool tips.
  * Do gradient fills.
  * Control focus, e.g., stop the buttons getting focus so you can "click" a 
tile with the Spacebar. (The current workaround is to press 'd' for delete 
tile.)
  * Enable/disable buttons, e.g., disable the Options dialog's OK button if any 
option is invalid.



Despite the above, given how small and convenient NiGui is, and how it can be 
used to create stand-alone GUI executables, I think it is a superb library.

And I'm also enjoying learning Nim very much!


Re: indentation

2019-12-14 Thread marks
I converted my nim files to 2 spaces using nimpretty. However, I found it will 
only do one file at a time!


indentation

2019-12-14 Thread marks
In an earlier post I wrote:

_" PS I use 4 spaces for indents because I read years ago in Code Complete that 
comparative studies had shown that a minimum of 3 is needed for clarity, and 
I'm used to 4 from Python;-}"_

I rechecked the reference and found that my note above was **incorrect**. 
According to _Code Complete_ second edition (page 737):

  * _" Indentation has been shown to be correlated to increased programmer 
comprehension."_ (and he quotes the study)
  * _" The study concluded that two-to-four space indentation was optimal."_



So, from now on, for Nim I'll use the Nim standard of two spaces.


Why inherit RootObj?

2019-12-13 Thread marks
According to the manual 
[https://nim-lang.org/docs/system.html#RootObj](https://nim-lang.org/docs/system.html#RootObj)

"Objects should inherit from RootObj or one of its descendants."

Why is this?

The next sentence is:

"However, objects that have no ancestor are also allowed."

I've been doing this without problems.


Re: What does "cannot be captured as it would violate memory safety" mean?

2019-12-11 Thread marks
The variable is sent as a var to a proc where it works fine. But I then in that 
proc I pass it to another proc and in that one I get the error. I've also tried 
passing it to the other proc without var (since in that data is only read) but 
get the same error. Is there an alternative to var that would work?


What does "cannot be captured as it would violate memory safety" mean?

2019-12-11 Thread marks
In some situations I get the error message _" cannot be captured as it would 
violate memory safety"_. I understand that this means nim is trying to stop me 
shooting myself in the foot, but is there anywhere I can read an explanation 
and if it is possible to do what I want without triggering this error?


Re: Recommended GUI library?

2019-12-11 Thread marks
OK, thanks. Docs ought to mention that.


Re: Recommended GUI library?

2019-12-11 Thread marks
QML depends on Qt which is big (like wx) compared to, say NiGui. Also Qt's 
mutli-license is a problem for some people.


Re: Recommended GUI library?

2019-12-10 Thread marks
I tried your hello example on Linux and it works fine.

But on Windows the same code gives this error: `could not load: SDL2.dll`.

My nim bin folder (containing the SDL*.dlls) in on my PATH.

I then copied SDL2*.dll from nim's bin folder to the same folder as the 
hello.nim but it still gave the same error.


NiGui examples?

2019-12-10 Thread marks
Has anyone built any NiGui apps that are bigger & more realistic than the 
examples? If so and they're FOSS, could you provide some links so I can study 
them?

All the examples use global vars to maintain state across controls. But this 
doesn't scale well or work well with large apps.

  * how do you subclass correctly -- or if this goes against the grain for 
NiGui, what is the correct approach to use instead?
  * how do you communicate between controls or maintain state without globals?




Re: Recommended GUI library?

2019-12-09 Thread marks
I'm starting to experiment with NiGui. I'm trying to create "widgets" that 
maintain some state and that can communicate events between the child widgets 
they contain. I also want to modularise the code into separate functions and 
objects. Here's my first hack on your example 10 (see also a question in the 
code & notes after the code): 


{.experimental: "codeReordering".}

import nigui

type
MainWindow = object
window: Window
statusLabel: Label
CustomControl = object
control: Control

proc main(): void =
app.init()
var mainWindow = newMainWindow("Test #2")
mainWindow.statusLabel.text = "Click..."
mainWindow.window.show()
app.run()

proc newMainWindow(title: string): MainWindow =
result.window = newWindow(title)
result.window.width = 500
result.window.height = 500
var vbox = newLayoutContainer(LayoutVertical)
result.window.add(vbox)
result.statusLabel = newLabel()
vbox.add(result.statusLabel)

# pass in the label so that the new control can "talk: to it: is there 
a better way?
var control = newCustomControl(result.statusLabel)
control.control.width = 400
control.control.height = 400
vbox.add(control.control)
control.control.widthMode = WidthMode_Fill
control.control.heightMode = HeightMode_Fill

proc newCustomControl(label: Label): CustomControl =
result.control = newControl()

result.control.onDraw = proc (event: DrawEvent) =
let canvas = event.control.canvas
canvas.areaColor = rgb(30, 30, 30) # dark grey
canvas.fill()
canvas.setPixel(0, 0, rgb(255, 0, 0))
canvas.areaColor = rgb(255, 0, 0) # red
canvas.drawRectArea(10, 10, 30, 30)
canvas.lineColor = rgb(255, 0, 0) # red
canvas.drawLine(60, 10, 110, 40)
let text = "Hello World!"
canvas.textColor = rgb(0, 255, 0) # lime
canvas.fontSize = 20
canvas.fontFamily = "Arial"
canvas.drawText(text, 10, 70)
canvas.drawRectOutline(10, 70, canvas.getTextWidth(text),
   canvas.getTextLineHeight())

result.control.onMouseButtonDown = proc (event: MouseEvent) =
label.text = $event.button & " (" & $event.x & ", " & $event.y & ")"
# Shows where the mouse is clicked in control-relative coordinates

main()


Run

You'll notice that I had to drop the images since I couldn't get them to work 
(even though they work fine in your original example). Oh, and this runs fine 
on Windows & Linux:-)

PS I use 4 spaces for indents because I read years ago in _Code Complete_ that 
comparative studies had shown that a minimum of 3 is needed for clarity, and 
I'm used to 4 from Python;-}


Re: Recommended GUI library?

2019-12-09 Thread marks
I didn't even know there was a wxWidgets port. When I searched the nimble 
package site for "gui" it didn't find it (maybe it isn't there) and nor is it 
mentioned in the Curated Packages. Probably good if you put it in one or both 
those places so people could find it:-)

Also might help if you list the .so's, .dylib's and .DLLs that need to be 
distributed with an nim executable.

Anyway, I'll give it a try!


Re: Recommended GUI library?

2019-12-09 Thread marks
I've now tried the "hello world" program for all those that claim to be 
cross-platform (at least Linux & Windows). Most don't actually work on Windows, 
and all but one requires at least one `.so` or `.dll`.

The one exception is [NiGui](https://github.com/trustable-code/NiGui). This is 
pure Nim so doesn't need any extra shared libraries. Also, I found it worked 
fine on both Linux and Windows. I haven't tested it for performance or for 
comprehensiveness, and the documentation is rather sparse. However, it comes 
with a whole bunch of examples which are small enough to study and learn from.

I really hope that _NiGUI_ gets the support it needs. For example, after 
decades, Python still has no native GUI library (although there have been many 
attempts, e.g., _PyGUI_ ). This makes it much harder to deploy Python GUI apps. 
Yet with _NiGUI_ deployment is easy since it is built right into the executable 
with no separate libraries.


Recommended GUI library?

2019-12-08 Thread marks
Is there a recommended GUI library for nim?

I notice that with a Windows install one of the DLLs is libui.dll, but there're 
also SDL2 DLLs. I'm looking for a GUI library that I can use to build apps on 
Linux and Windows (don't need macOS).


Nim 1.1+ roadmap?

2019-12-08 Thread marks
Did a Nim 1.1+ roadmap get published? I can't see one in the blog and don't 
know where else to look.

Is the experimental _codeReordering_ likely to be adopted; I've just started to 
use it and find it very useful.


Re: Manual query "deviated" ?

2019-12-08 Thread marks
OK, I've done two patches (since two files needed to be changed --- I'm not 
much of a github user). 
[https://github.com/nim-lang/Nim/pull/12845](https://github.com/nim-lang/Nim/pull/12845)
 
[https://github.com/nim-lang/Nim/pull/12846](https://github.com/nim-lang/Nim/pull/12846)
 If I see other typos or problems with English I'll try to do PRs for them in 
future. 


Manual suggestion re exceptions

2019-12-08 Thread marks
In the manual it doesn't say that you can create your own custom exceptions. 
Personally, I prefer to create my own so that I am clear whether it is from 
nim's code or mine. Someone has shown how to create custom exceptions: 
[https://forum.nim-lang.org/t/2863#17814](https://forum.nim-lang.org/t/2863#17814)
 I think something like this ought to be in the Exceptions section of the 
manual.


Re: Manual query "deviated" ?

2019-12-08 Thread marks
"derived" kind of means or imlies "inherited", so if you don't like "determined 
by", I'd suggest one of these:

  * " ok, based on the first parameter"
  * " ok, based on the type of the first parameter"
  * " ok, based on the first parameter's type"



Plus, of course, similar changes to the text in the preceding para.


Manual query "deviated" ?

2019-12-07 Thread marks
In the manual there's this example: 


proc forward[T](x: var T): var T =
  result = x # ok, deviated from the first parameter.


Run

The word _deviated_ is also used in the text above. But these uses all seem 
wrong to me. I _think_ the above comment ought to be `# ok, determined from 
...` or `# ok, determined by ...`, and similarly in the text?


Re: Is it possible to browse the nimble.directory?

2019-12-07 Thread marks
Thanks for your helpful replies: and to the others who've replied to my other 
questions.


Is it possible to browse the nimble.directory?

2019-12-07 Thread marks
The [https://nimble.directory](https://nimble.directory)/ has a good search 
function, but in reaquainting myself with nim I'd like to be able to see 
categories and browse. Is this possible?


What are the compiler defaults? etc...

2019-12-07 Thread marks
  * In 
[https://nim-lang.org/docs/nimc.html](https://nim-lang.org/docs/nimc.html) it 
shows all the compiler options, but it doesn't seem to show the defaults. How 
can I find out what they are?
  * Is there a pragma that would force names to be fixed? For example, if I do 
_import mod_ and get **afunc** in my namespace, what I also get in effect is 
**aFUNC** , **aFunc** , etc., whereas I'd prefer just one. (I realise this is 
unlikely to be available or even possible.)
  * Is there any _runtime_ cost in doing _import mod_ compared with _from mod 
import foo, bar_? Is _import mod_ recommended rather than _from mod import ..._?
  * On Windows I used the prebuilt .zip but on Linux I built it myself. I think 
it might be worth adding to the instructions to run _. /koch nimble_ since _. 
/koch tools_ doesn't seem to build nimble.
  * Incidentally I tried nim a couple of years ago and gave up mainly because I 
couldn't get it to reliably install on Windows. Now I've installed on Linux and 
Windows and _finish.exe_ works fine. It gave an error when it came to fetch 
mingw but instead of giving up it offered to get it from nim's site and when I 
said yes it "just worked". What I'm looking for is a language as convenient and 
fast to develop with as Python but with static typing, easy deployment (single 
executable), and C-speed runtime. Which is why I'm trying nim again.




Which is the preferred style: call(x) or call x

2019-12-06 Thread marks
I've found that when I have a call with a single argument, say, myfunc(x), I 
can change it to myfunc x. This surprised me since coming from Python I'd have 
thought myfunc is a reference to the function, but clearly that's not the case 
with nim. (So, how do you get a function reference?) But out of the two call 
syntaxes, which is to be preferred?