def get_field_info(ar, column_names=None):
        def getit():

            if ar.request is None:
                columns = None
            else:
                data = getrqdata(ar.request)
                columns = [
                    six.text_type(x) for x in
                    data.getlist(constants.URL_PARAM_COLUMNS)]
            if columns:
                all_widths = data.getlist(constants.URL_PARAM_WIDTHS)
                hiddens = [(x == 'true') for x in data.getlist(
                    constants.URL_PARAM_HIDDENS)]
                fields = []
                widths = []
                ah = ar.actor.get_handle()
                for i, cn in enumerate(columns):
                    col = None
                    for e in ah.list_layout.main.columns:
                        if e.name == cn:
                            col = e
                            break
                    if col is None:
                        raise Exception("No column named %r in %s" %
                                        (cn, ar.ah.list_layout.main.columns))
                    if not hiddens[i]:
                        fields.append(col)
                        widths.append(int(all_widths[i]))
            else:
                if column_names:
                    from lino.core.layouts import ColumnsLayout
                    ll = ColumnsLayout(column_names, datasource=ar.actor)
                    lh = ll.get_layout_handle(settings.SITE.kernel.default_ui)
                    columns = lh.main.columns
                    columns = [e for e in columns if not e.hidden]
                else:
                    ah = ar.actor.get_request_handle(ar)
                    columns = ah.list_layout.main.columns

                # render them so that babelfields in hidden_languages
                # get hidden:
                for e in columns:
                    e.value = e.ext_options()
                #
                columns = [e for e in columns if not
                           e.value.get('hidden', False)]

                columns = [e for e in columns if not e.hidden]

                widths = ["%d" % (col.width or col.preferred_width)
                          for col in columns]
                #~ 20130415 widths = ["%d%%" % (col.width or col.preferred_width) for col in columns]
                #~ fields = [col.field._lino_atomizer for col in columns]
                fields = columns

            headers = [column_header(col) for col in fields]

            oh = ar.actor.override_column_headers(ar)
            if oh:
                for i, e in enumerate(columns):
                    header = oh.get(e.name, None)
                    if header is not None:
                        headers[i] = header
                #~ print 20120507, oh, headers

            return fields, headers, widths
    
        u = ar.get_user()
        if u is None:
            return getit()
        else:
            return jsgen.with_user_profile(u.profile, getit)
Return a tuple `(fields, headers, widths)` which expresses which
dataset/ETHPy150Open lsaffre/lino/lino/core/tablerequest.py/TableRequest.get_field_info